/**
 * 页面实现，用来替换newPro.js
 * 
 *  - 首页
 *  - 登录
 *  - 商城资源列表panel
 *  - layamaker项目，创建项目panel
 */
class layaPage {
    constructor() {
        this.path = require('path');
        this.editPageDir = this.path.join(__dirname, '../', '../', '../', '../', 'layarepublic', 'editPage');

        this.homePageIndexEle = null;
        this.createBtnEle = null;
        this.openBtnEle = null;
        this.recentListEle = null;
        this.tabBtnListEle = null;
        this.homePageWrapperEle = null;
        this.contentWrapper = null;
        this.IS_LOGIN_SUCCESS_STR = 'isLoginSuccess';

        this.eventFunc = {};
        this.shopInfoObj = {};

        this.homepageTabBarType = window.globalMode === "cloud" ? 'sample' : 'news'; // 主页，右侧tabbar
        this.localStorageRecentStr = window.globalMode === "cloud" ? 'makerRecentOpenList' : 'layarecentOpenList';
        this.mainInfo = null; // 从服务器获取的信息
        this.shopType;
    }

    /**
     * 首页
     * out/layarepublic/editPage/homepage
     */
    createLayaIndexHTML() {
        this.homepageTabBarType =  window.globalMode === codeMain.globalModeType.layamaker ? 'sample' : 'news';
        sessionStorage.setItem('isShowHomePage', 'create');
        this.homePageIndexEle = document.getElementById('homePageIndex');
        this.homePageIndexEle.style.display = 'block';

        let homePage = this.path.join(this.editPageDir, 'homepage', 'index.html');
        let fs = require('fs');
        fs.readFile(homePage, 'utf8', (err, data) => {
            if (!!err) {
                return;
            }
            this.homePageIndexEle.innerHTML = `
                <div class="homepage-main-area">
                    <div class="left-content">
                        <div class="button-content">
                            <div class="creat-btn">
                                <div class="create-project-img"></div>
                                <span class="btn-name">${codeMain.getPanelLang(324)}</span>
                            </div>
                            <div class="open-btn">
                                <div class="open-project-img"></div>
                                <span class="btn-name">${codeMain.getPanelLang(354)}</span>
                            </div>
                        </div>
                        <div class="recent-content-title-content">
                            <div class="recent-content-title">${codeMain.getPanelLang(355)}</div>
                        </div>
                        <div id="recentList"></div>
                    </div>
                    <div class="right-content">
                        <div class="btn-list">
                            ${window.globalMode === codeMain.globalModeType.layamaker ? `
                            <div class="sample-item right-btn-item select" data-type="sample">
                                <span>${codeMain.getPanelLang(356)}</span>
                                <div class="item-image"></div>
                            </div>
                            <div class="study-item right-btn-item" data-type="study">
                                <span>${codeMain.getPanelLang(357)}</span>
                                <div class="item-image"></div>
                            </div>
                            <div class="community-item right-btn-item" data-type="community">
                                <span>${codeMain.getPanelLang(358)}</span>
                                <div class="item-image"></div>
                            </div>
                            ` : `
                            <div class="news-item right-btn-item select" data-type="news">
                                <div class="item-image"></div>
                                <span>${codeMain.getPanelLang(359)}</span>
                            </div>
                            <div class="study-item right-btn-item" data-type="study">
                                <div class="item-image"></div>
                                <span>${codeMain.getPanelLang(357)}</span>
                            </div>
                            <!-- <div class="community-item right-btn-item" data-type="community">
                                <div class="item-image"></div>
                                <span>${codeMain.getPanelLang(358)}</span>
                            </div> -->
                            `}
                        </div>
                        <div class="content-wrapper">
                        </div>
                    </div>
                </div>
            `;

            this.createBtnEle = this.homePageIndexEle.getElementsByClassName('creat-btn')[0];
            this.openBtnEle = this.homePageIndexEle.getElementsByClassName('open-btn')[0];
            this.recentListEle = document.getElementById('recentList');
            this.tabBtnListEle = this.homePageIndexEle.getElementsByClassName('btn-list')[0];
            this.homePageWrapperEle = this.homePageIndexEle.getElementsByClassName('content-wrapper')[0];
            this.contentWrapper = this.homePageIndexEle.getElementsByClassName('content-wrapper')[0];
            this.bindLayaIndexEventListener();

            // 最近打开列表
            let 
                recentListStr = localStorage.getItem(this.localStorageRecentStr),
                recentList;
                try {
                    recentList = (recentListStr && JSON.parse(recentListStr)) || [];
                } catch(e) {
                    recentList = [];
                }
            // 如果是旧的最近打开列表信息
            if (recentList[0] && typeof recentList[0] == 'string') {
                localStorage.setItem(this.localStorageRecentStr, "");
                recentList = [];
            }
            this.createRecentHTML(recentList);

            // 右侧展示信息
            this.getHomePageInfo((infoObj) => {
                if (window.globalMode === codeMain.globalModeType.layamaker) {
                    if (!infoObj.sample || !infoObj.study || !infoObj.community) {
                        return;
                    }
                } else {
                    // let infoObj = info && JSON.parse(info);
                    if (!infoObj.news || !infoObj.study || !infoObj.community) {
                        return;
                    }
                }
                this.mainInfo = infoObj;
                this.createTabAreaHTML();
            });
        });
    }
    createRecentHTML(recentList) { // 左侧最近打开项目
        let recentLength = recentList.length,
            recentHTMLStr = '',
            recentName,
            recentAddr,
            appId; // layamaker项目使用
        for (let i = 0; i < recentLength; i++) {
            recentName = recentList[i].proName || recentList[i].game_name;
            appId = recentList[i].appid;
            recentAddr = recentList[i].path || this.getProjectPathByAppId(appId);
            recentHTMLStr += `
            <div class="recent-item" data-addr="${recentAddr}" data-appId="${appId}">
                <div class="recent-item-main">
                    <div class="recent-item-image"></div>
                    <div class="recent-item-info">
                        <div class="recent-item-name">${recentName}</div>
                        <div class="recent-item-addr">${recentAddr}</div>
                    </div>
                </div>
                <div class="recent-item-operate-list-btn">
                    <div class="recent-item-wrapper">
                        <div class="recent-item-open-img" data-type="open"></div>
                    </div>
                    <div class="recent-item-wrapper">
                        <div class="recent-item-del-img" data-type="delete"></div>
                    </div>
                </div>
            </div>
            `;
        }
        if (!recentHTMLStr) {
            recentHTMLStr = `
            <div class="recent-hint">
                找不到历史项目<br />
                请点击上面 “新建” 项目<br />
                或者 “打开” 已有项目
            </div>
            `;
        }
        this.recentListEle && (this.recentListEle.innerHTML = recentHTMLStr);
    }
    createTabAreaHTML() { // 右侧信息区域
        if (!this.mainInfo || !this.isHomePageShow()) {
            return;
        }
        let showInfoList = this.mainInfo[this.homepageTabBarType];
        let innerHTML = '';
        for (let j = 0; j < showInfoList.length; j++) {
            if (showInfoList[j].type == 'headlines') {
                // 大图部分
                let 
                    showInfoObj = showInfoList[j].contents,
                    length = showInfoObj.length;
                innerHTML += '<div class="big-image-wrapper">';
                for (let i = 0; i < length; i++) {
                    innerHTML += `
                    <div class="big-image-item" data-url="${showInfoObj[i].url}">
                        <div style="width: 100%;height: 100%;">
                            <img class="big-image" src="${showInfoObj[i].image}"/>
                        </div>
                        <div class="big-image-bottom-content">${showInfoObj[i].title}</div>
                    </div>
                    `;
                }
                innerHTML += '</div>';
            }
            if (showInfoList[j].type == 'contents') {
                // 小图部分
                let 
                    showInfoObj = showInfoList[j].contents,
                    length = showInfoObj.length;
                innerHTML += '<div class="small-image-wrapper">';
                for (let i = 0; i < length; i++) {
                    innerHTML += `
                    <div class="small-image-item-wrapper" data-url="${showInfoObj[i].url}">
                        <div class="small-image-item-content">
                            <div style="width: 100%; background-color: #fff;">
                                <img class="small-img-item" src="${showInfoObj[i].image}"/>
                            </div>
                            <div class="small-image-bottom-content">${showInfoObj[i].title ? showInfoObj[i].title : ''}</div>
                        </div>
                        <div class="small-content-wrapper">
                            <div class="small-content-name">${showInfoObj[i].intro ? showInfoObj[i].intro : ''}</div>
                            <div class="small-content-des">${showInfoObj[i].des ? showInfoObj[i].des : ''}</div>
                        </div>
                    </div>
                    `;
                }
                innerHTML += '</div>';
            }
        }
        this.homePageWrapperEle.innerHTML = innerHTML;
    }
    bindLayaIndexEventListener() {
        this.eventFunc['createProClick'] = () => {
            // NewProLaya();
            codeMain.createProHandler();
        };

        this.eventFunc['openProClick'] = () => {
            let _extensions;
            if (window.globalMode === codeMain.globalModeType.layamaker) {
                _extensions = ['layamaker']
            }
            codeMain.openProLaya(_extensions);
        };

        this.eventFunc['recentListClick'] = (e) => {
            const deleteItem = (addr, target) => {
                let 
                    recentListStr = localStorage.getItem(this.localStorageRecentStr),
                    recentList = (recentListStr && JSON.parse(recentListStr)) || [],
                    length = recentList.length,
                    index = -1;
                for (let i = 0; i < length; i++) {
                    if(recentList[i].path == addr) {
                        index = i;
                        break;
                    }
                }
                if (index !== -1) {
                    recentList.splice(index, 1);
                    localStorage.setItem(this.localStorageRecentStr, JSON.stringify(recentList));
                    target.className += " delete";
                    setTimeout(() => {
                        target.remove();
                    }, 500);
                    codeMain.updateRecentOpenList();
                    // 所有的最近打开列表项目都被删掉了
                    if (recentList.length == 0) {
                        let recentHTMLStr = `
                        <div class="recent-hint">
                            找不到历史项目<br />
                            请点击上面 “新建” 项目<br />
                            或者 “打开” 已有项目
                        </div>
                        `;
                        setTimeout(() => {
                            this.recentListEle.innerHTML = recentHTMLStr;
                        }, 500);
                    }
                }
            }
            let 
                addr,
                target = e.target,
                isDelete = false, // 是否删除记录
                isOpen = false, // 是否打开记录
                appId;
            for (let i = 0; i < 5; i++) {
                if (target.id == 'recentList') { // 如果是list元素，return
                    break;
                }
                appId = target.getAttribute('data-appId');
                addr = target.getAttribute('data-addr');
                isDelete = isDelete || target.getAttribute('data-type') == 'delete';
                isOpen = isOpen || target.getAttribute('data-type') == 'open';
                if (addr) {
                    break;
                }
                target = target.parentElement;
            }
            if (isDelete && addr) { // 删除记录
                deleteItem(addr, target);
            } else if (isOpen && addr) { // 打开文件夹
                codeMain.shell.showItemInFolder(addr);
            } else if (addr) { // 打开项目
                if (window.globalMode === codeMain.globalModeType.layamaker) { // layamaker模式
                    if (appId === sessionStorage.getItem('appId')) {
                        let uiCodeMenuEle = document.getElementsByClassName('leftBoxBar')[0].childNodes[6];
                        uiCodeMenuEle.click();
                        return;
                    }
                    sessionStorage.setItem('appId', appId);
                    // 如果没有对应文件夹，创建，uicode部分负责下载
                    try {
                        codeMain.mkdirsSync(addr);
                    } catch(e) {
                    }
                    codeMain._codechannel.openWindow([addr]);
                    return;
                }
                if (addr == codeMain.workspacePath) {
                    let codeMenuEle = document.getElementsByClassName('leftBoxBar')[0].childNodes[3];
                    codeMenuEle.click();
                    return;
                }
                codeMain._codechannel.openWindow([addr]);
                // 如果打不开这个项目，则从最近列表中删除该项
                // 打开项目中的then/done方法获取不到error事件，只能使用这个方式，如果有其他方式优先使用其他方式
                // 逻辑是：如果能够打开该项目，则IDE会刷新，setTimeout不会执行；如果没有刷新，说明不能够打开，删除该项
                setTimeout(() => {
                    deleteItem(addr, target);
                }, 3000);
            }
        };

        this.eventFunc['tabChange'] = (e) => {
            let 
                target = e.target,
                type;
            for (let i = 0; i < 5; i++) {
                if (target.className && target.className.indexOf('btn-list') !== -1) { // 如果是list元素，return
                    return;
                }
                type = target.getAttribute('data-type');
                if (type) {
                    break;
                }
                target = target.parentElement;
            }
            if (target.className && target.className.indexOf('select') !== -1) { // 点击的就是选中的
                return;
            }
            let selectEle = this.tabBtnListEle.getElementsByClassName('select')[0];
            selectEle.className = selectEle.className.replace(' select', '');
            target.className += ' select';
            this.homepageTabBarType = type;
            this.createTabAreaHTML();
        };

        this.eventFunc['contentClick'] = (e) => {
            let 
                target = e.target,
                url;
            for (let i = 0; i < 8; i++) {
                if (target.className && target.className == 'content-wrapper') { // 如果是包裹元素，return
                    return;
                }
                url = target.getAttribute('data-url');
                if (url) {
                    break;
                }
                target = target.parentElement;
            }
            url && window.open(url);
        };

        // 新建项目
        this.createBtnEle.addEventListener('click', this.eventFunc['createProClick']);

        // 打开项目
        this.openBtnEle.addEventListener('click', this.eventFunc['openProClick']);

        // 打开最近项目
        this.recentListEle.addEventListener('click', this.eventFunc['recentListClick']);

        // 右侧tab转换-新闻、学习、社区
        this.tabBtnListEle.addEventListener('click', this.eventFunc['tabChange']);

        // tab内容区域，点击事件，浏览器打开
        this.contentWrapper.addEventListener('click', this.eventFunc['contentClick']);
    }
    destory() {
        if (!this.isHomePageShow()) {
            return;
        }
        this.createBtnEle && this.createBtnEle.removeEventListener('click', this.eventFunc['createProClick']);
        this.openBtnEle && this.openBtnEle.removeEventListener('click', this.eventFunc['openProClick']);
        this.recentListEle && this.recentListEle.removeEventListener('click', this.eventFunc['recentListClick']);
        this.tabBtnListEle && this.tabBtnListEle.removeEventListener('click', this.eventFunc['tabChange']);
        this.contentWrapper && this.contentWrapper.removeEventListener('click', this.eventFunc['contentClick']);

        this.homePageIndexEle.style = '';
        this.homePageIndexEle.innerHTML = '';

        this.homePageIndexEle = null;
        this.createBtnEle = null;
        this.openBtnEle = null;
        this.recentListEle = null;
        this.tabBtnListEle = null;
        this.homePageWrapperEle = null;
        this.contentWrapper = null;
    }
    isHomePageShow() {
        if (!!this.homePageIndexEle) {
            return true;
        }
        return false;
    }
    getHomePageInfo(func) {
        // 获取主页
        // 先从本地去取缓存的文件，然后去网络拉去最新的文件，并将最新的文件记入本地
        if (window.globalMode === codeMain.globalModeType.layamaker) {
            let path = require('path');
            let sampleInfo = path.join(this.editPageDir, 'homepage', 'config', 'sample.json');
            let stydyInfo = path.join(this.editPageDir, 'homepage', 'config', 'study.json');
            let communityInfo = path.join(this.editPageDir, 'homepage', 'config', 'community.json');
            let homePageInfo = {
                "sample": sampleInfo,
                "study": stydyInfo,
                "community": communityInfo
            };
            let fs = require('fs');
            let dataInfo = {};
            for (let item in homePageInfo) {
                fs.readFile(homePageInfo[item], 'utf8', (err, data) => {
                    if (!!err) {
                        return;
                    }
                    dataInfo[item] = JSON.parse(data);
                    func(dataInfo);
                });
            }
            let params = {
                URL: {
                    "sample": `${codeMain.URLObj.downIDEURL}/ideinfo/sample.json?v=${Math.random()}`,
                    "study": `${codeMain.URLObj.downIDEURL}/ideinfo/study.json?v=${Math.random()}`,
                    "community": `${codeMain.URLObj.downIDEURL}/ideinfo/community.json?v=${Math.random()}`
                },
                homePageInfo,
                fs
            };
            setTimeout(() => {
                this.getInfoFromServer(params, func);
            }, 1000);
            return;
        }
        let path = require('path');
        let newsInfo = path.join(this.editPageDir, 'homepage', 'config', 'news.json');
        let stydyInfo = path.join(this.editPageDir, 'homepage', 'config', 'study.json');
        let communityInfo = path.join(this.editPageDir, 'homepage', 'config', 'community.json');
        let homePageInfo = {
            "news": newsInfo,
            "study": stydyInfo,
            "community": communityInfo,
        };
        let fs = require('fs');
        let dataInfo = {};
        for (let item in homePageInfo) {
            fs.readFile(homePageInfo[item], 'utf8', (err, data) => {
                if (!!err) {
                    return;
                }
                dataInfo[item] = JSON.parse(data);
                func(dataInfo);
            });
        }
        let params = {
            URL: {
                "news": `${codeMain.URLObj.downIDEURL}/ideinfo/news.json?v=${Math.random()}`,
                "study": `${codeMain.URLObj.downIDEURL}/ideinfo/study.json?v=${Math.random()}`,
                "community": `${codeMain.URLObj.downIDEURL}/ideinfo/community.json?v=${Math.random()}`,
            },
            homePageInfo,
            fs
        };
        setTimeout(() => {
            this.getInfoFromServer(params, func);
            let updatePubPath = path.join(__dirname, "../", "../", "../", "../", "layarepublic", "updatepub", "index.js");
            let _fork = codeMain.childprocess.fork(updatePubPath);
            _fork.send("updatecon");
        }, 1000);
    }
    getInfoFromServer(infoObj, func) { // 获取网络请求
        let dataInfo = {};
        for (let item in infoObj.URL) {
            let xhr = new XMLHttpRequest();
            xhr.open("GET", infoObj.URL[item], true);
            xhr.onreadystatechange = function(e) {
                if (xhr.readyState==4 && xhr.status==200) {
                    let response = xhr.responseText;
                    if (!response) {
                        return;
                    }
                    dataInfo[item] = JSON.parse(response);
                    // func instanceof Function && func(dataInfo);
                    // 写入本地文件
                    if (infoObj.homePageInfo[item] && infoObj.fs && dataInfo[item]) {
                        infoObj.fs.writeFile(infoObj.homePageInfo[item], response, 'utf8', (err) => {
                            if (!!err) {
                                return;
                            }
                        });
                    }
                } 
            };
            xhr.send(null);
            xhr.onerror = function(e) {
            }
        }
    }

    /**
     * 登录界面
     * 登录界面是其他组实现的，使用webview封装
     */
    createLayaLoginHTML(params) { // 登录页面
        let isClickToShow = params && params.show;
        if (localStorage.getItem(this.IS_LOGIN_SUCCESS_STR) && !isClickToShow) { // 已经登录了，并且没有点击按钮
            return;
        }
        // codeMain.globalModeType.layamaker
        if (sessionStorage.getItem('isNotLogin') && !isClickToShow && window.globalMode !== codeMain.globalModeType.layamaker) { // 选择了本次暂不登录，并且不是点击菜单栏的登录按钮，并且不是layamaker模式下
            return;
        }
        this.loginPageEle = document.getElementById('loginPage');
        let path = require('path');
        if (!localStorage.getItem(this.IS_LOGIN_SUCCESS_STR)) { // 没有登录
            let loginPath = path.join(this.editPageDir, 'login', 'login.html');
            this.loginPageEle.innerHTML = `
            <div style="-webkit-app-region: drag; height: 30px; top: 0px; z-index: 9999999;width: calc(100% - 250px);position: absolute;right: 200px;left: 50px;"></div>
            <webview src="file://${loginPath}?mode=${window.globalMode}" style="width:100%; height:100%;${codeMain.getIDETheme() === "light" ? 'background-color: #fff;': ''}"></webview>
            `;
            // 隐藏用户按钮和打赏按钮
            document.getElementById("avatarWrapper").style.display = "none";
        } else { // 登录成功状态
            this.loginPageEle.className += ' part-transparent';
            let loginPath = path.join(this.editPageDir, 'login', 'userInfo.html');
            this.loginPageEle.innerHTML = `
            <div class="main-wrapper">
                <div style="-webkit-app-region: drag; height: 30px; top: 0px; z-index: 9999999;width: calc(100% - 250px);position: absolute;right: 200px;left: 50px;"></div>
                <webview src="file://${loginPath}" style="width:100%; height:100%;"></webview>
            </div>
            `;
        }
        this.loginPageEle.style.display = 'block';
        this.loginWebViewEle = this.loginPageEle.getElementsByTagName('webview')[0];
        this.loginWebViewEle.addEventListener('close', () => {
            this.destoryLoginHTMLShow();
        });
        this.loginWebViewEle.addEventListener('will-navigate', (url) => { // 跳转
            let _url = url;
            if (typeof _url == 'object') {
                _url = url.url;
            }
            this.loginWebViewEle.loadURL(_url);
        });
        this.loginWebViewEle.addEventListener('console-message', (event) => { 
            // 也可以使用 ipc-message , 但是 nodeintegration 使用 $ 符， 和 jquery 冲突
            this.handleLoginConsoleMessage(event.message);
        });
        this.eventFunc['logoutClick'] = (e) => {
            if (e.target.id === 'loginPage' && this.loginPageEle.className.indexOf('part-transparent') !== -1) { // 退出页面，点击了webview之外的区域
                this.destoryLoginHTMLShow();
            }
        }
        this.loginPageEle.addEventListener('click', this.eventFunc['logoutClick']);
    }
    isLayaLoginHTMLShow() {
        return !!this.loginPageEle;
    }
    destoryLoginHTMLShow() {
        if (!this.isLayaLoginHTMLShow()) {
            return;
        }
        sessionStorage.setItem('isNotLogin', 'true');
        this.loginPageEle.style.display = 'none';
        this.loginPageEle.className = this.loginPageEle.className.replace(' part-transparent', '');
        this.loginPageEle.removeEventListener('click', this.eventFunc['logoutClick']);
        this.loginPageEle = null;
        this.loginWebViewEle = null;
        // 显示用户按钮和打赏按钮
        document.getElementById("avatarWrapper").style.display = "block";
    }
    isIDELogin() {
        return !!localStorage.getItem(this.IS_LOGIN_SUCCESS_STR);
    }
    /**
     * @param {*} message 
     * 目的: 监听webview中的输出，如果符合处理条件，IDE做出对应处理
     * 使用: 登录、左侧栏的论坛
     */
    handleLoginConsoleMessage(message) {
        console.log('获取webview信息', message);
        try {
            message = JSON.parse(message);
        } catch (e) {
            message = {};
        }
        if (message.type == 'loginSuccess') { // 1) 登录webview，登录成功; 2)论坛，登录成功
            // 在这个地方或者刷新token时将登录成功信息存入本地，特殊处理username
            // 特殊处理微信登录
            message = this.handleLoginStrToJSON(message);
            if (!message.token) {
                return;
            }
            message.username = message.username || message.mobile || message.email || (message.channelExt && message.channelExt.nickname) || message.userId;
            message.devuid = message.devuid || message.uid;
            this.setLoginInfo(message);
            if (window.globalMode === codeMain.globalModeType.layamaker) { // 如果是layamaker模式，重新登录后需要设置信息
                window.cloudProject = {
                    userId: message && message.userId,
                    username: message.username,
                    appId: sessionStorage.getItem('appId')
                };
            } else if (!message.devuid) { // 只有在登录的时候回没有devuid(uid)，其他时候都有
                let info = this.getLoginInfo();
                let isVIP = false;
                if (info && info.is_vip === 1) {
                    isVIP = true;
                }
                sessionStorage.removeItem("getMasterTokenTime");
                codeMain.regLogin(isVIP); // 正常模式下，如果没有uid，刷新一下
            }
        } else if (message.type == 'regLoginInfo') { // 1) 充值成功 2) 登录刷新uid后，如果是VIP，需要绑定uuid
            let info = this.getLoginInfo();
            let isVIP = false;
            if (info && info.is_vip === 1) {
                isVIP = true;
            }
            sessionStorage.removeItem("getMasterTokenTime");
            codeMain.regLogin(isVIP); // webview更新了登录信息，比如充值了VIP
        } else if (message.type == 'deleteLoginSuccess') { // 1) 登录webview，登出页面，退出按钮; 2) 论坛，退出
            localStorage.removeItem(this.IS_LOGIN_SUCCESS_STR);
            localStorage.removeItem("userLoginInfoStr");
            if (window.globalMode === codeMain.globalModeType.layamaker) {
                // 如果是layamaker模式，退出登录，很多功能将不能使用
                window.cloudProject = null;
                // 强制登录
                this.destoryLoginHTMLShow();
                let params = {
                    show: true,
                };
                codeMain.layaPageIns.createLayaLoginHTML(params);
            }
        } else if (message.type == 'deleteAndRestart') { // 登录webview，登出页面会调用
            localStorage.removeItem(this.IS_LOGIN_SUCCESS_STR);
            this.destoryLoginHTMLShow();
            let params = {
                show: true,
            };
            codeMain.layaPageIns.createLayaLoginHTML(params);
            if (window.globalMode === codeMain.globalModeType.layamaker) {
                // 如果是layamaker模式，退出登录，很多功能将不能使用
                window.cloudProject = null;
            }
        } else if (message.type == 'developers_login') { // 1) LAYA开放平台，強制登录
            // 未登录情况下，调用登录页面，点击了稍后登录，弹出“该功能需要登录才能使用”
            // 登录情况下，webview输出该console，cookie过期，删除localStorage，重新登录
            localStorage.removeItem(this.IS_LOGIN_SUCCESS_STR);
            let params = {
                show: true,
            };
            codeMain.layaPageIns.createLayaLoginHTML(params);
        } else if (message.type == "rechargeVIP") { // 充值VIP
            codeMain.rechargeVIP();
        } else if (message.type === "invoice") { // 开发票
            codeMain.invoice();
        } else if (message.type === "openurl") {
            message.url && codeMain.remote.shell.openExternal(message.url);
        }
    }
    logoutAndReLogin() { // 退出并重新登录
        localStorage.removeItem(this.IS_LOGIN_SUCCESS_STR);
        this.destoryLoginHTMLShow();
        let params = {
            show: true,
        };
        codeMain.layaPageIns.createLayaLoginHTML(params);
    }
    handleLoginStrToJSON(msg) { // 处理登录成功信息
        let message;
        try {
            message = typeof msg == 'object' ? msg :  JSON.parse(msg);
        } catch (e) {
            message = {};
        }
        if (!message.token) {
            if (message.userInfo) {
                return this.handleLoginStrToJSON(message.userInfo);
            }
            return {};
        }
        return message;
    }

    /**
     * maker 通用配置类型
     */
    get makerInfoObj() {
        return {
            model: { // 模型
                title: codeMain.getPanelLang(313),
                _classId: "10",
                isSingleFile: false,
                extensionList: [".lh"]
            },
            pic: { // 图片
                title: codeMain.getPanelLang(314),
                _classId: "11",
                isSingleFile: true,
                extensionList: ["jpg", "png"],
            },
            prefab: { // 模板
                title: codeMain.getPanelLang(315),
                _classId: "12",
                isSingleFile: false,
                extensionList: [".prefab"]
            },
            ani: { // 动画
                title: codeMain.getPanelLang(316),
                _classId: "13",
                isSingleFile: false,
                extensionList: [".ani"]
            },
            part: { // 粒子
                title: codeMain.getPanelLang(317),
                _classId: "14",
                isSingleFile: false,
                extensionList: [".lh"]
            },
            sound: { // 声音
                title: codeMain.getPanelLang(318),
                _classId: "15",
                isSingleFile: true,
                extensionList: ["mp3", "wav"],
            },
            ui: { // UI
                title: codeMain.getPanelLang(319),
                _classId: "16",
                isSingleFile: false,
            },
            font: { // font
                title: codeMain.getPanelLang(456),
                _classId: "17",
                isSingleFile: true,
                extensionList: ["ttf"],
            },
        }
    }

    /**
     * 商城
     */
    createPopUpShopHTML(type, _isShowMyList) {
        console.log(`%c codeMain.layaPageIns.createPopUpShopHTML("${type}", ${_isShowMyList})`, "color: green;");
        let isPass = this.checkShopCanShow();
        if (!isPass) {
            return;
        }
        if (_isShowMyList) {
            sessionStorage.setItem("isShowMyList", "true");
        } else {
            sessionStorage.removeItem("isShowMyList");
        }
        const TYPE_TEXT = this.makerInfoObj;
        if (type && TYPE_TEXT[type] instanceof Object) {
            this.shopType = type;
        } else {
            this.shopType = 'pic';
        }

        let isHideDetailSide = (this.shopType === "sound" && !_isShowMyList);
        this.popUpShopEle = document.getElementById('shop');
        this.popUpShopEle.innerHTML = `
            <div class="shop-wrapper-content ${_isShowMyList ? "shop-mylist-show" : ""}">
                <div class="common-tool-title">
                    <div class="common-tool-icon-wrapper">
                        <img class="common-tool-icon" title="资源管理" src="skins/default/image/ide/layamaker-newpro.png" style="width: 18px; height: 20px;">
                    </div>
                    <div class="common-tool-title-content">
                        ${TYPE_TEXT[this.shopType].title}
                        ${_isShowMyList ? "(mine-private)" : ""}
                    </div>
                    <div class="common-tool-close"></div>
                </div>
                <div class="shop-main-area">
                    <div class="shop-main-wrapper">
                        <div class="shop-nav"></div>
                        <div class="shop-header-wrapper">
                            <div class="shop-sub-nav"></div>
                            <div class="shop-header-search-wrapper">
                                <input />
                                <div class="img"></div>
                            </div>
                        </div>
                        <div class="shop-content-wrapper"></div>
                    </div>
                    <div class="shop-detail-wrapper" style="display: ${isHideDetailSide ? "none" : "block"};"></div>
                </div>
            </div>
        `;
        let 
            title = this.popUpShopEle.getElementsByClassName("common-tool-title")[0];
        __Layadrag(this.popUpShopEle, title);
        this.popUpShopEle.style.display = 'flex';
        this.popUpShopMainAreaEle = this.popUpShopEle.getElementsByClassName('shop-wrapper-content')[0]; // 用来获取子元素
        this.popUpShopMainEle = this.popUpShopMainAreaEle.getElementsByClassName('shop-main-area')[0]; // 用来监听事件
        this.popUpShopNavEle = this.popUpShopMainAreaEle.getElementsByClassName('shop-nav')[0];
        this.popUpShopSubNavEle = this.popUpShopMainAreaEle.getElementsByClassName('shop-sub-nav')[0];
        this.popUpShopContentEle = this.popUpShopMainAreaEle.getElementsByClassName('shop-content-wrapper')[0];
        this.popUpShopDetailEle = this.popUpShopMainAreaEle.getElementsByClassName('shop-detail-wrapper')[0];
        let _selectedClassId = this.makerInfoObj[this.shopType]._classId;
        this.shopInfoObj = {
            selectedClassId: _selectedClassId,
            selectedNavId: '', // 一级导航选中
            selectedSubNavId: '', // 二级导航选中
            pubResList: null,
            resNavSortObj: null, // 整理好的，准备显示的资源列表
        };
        this.bindShopEventListener();
        // 显示panel
        this.createMainContentHTML();
    }

    /**
     * layamaker资源商店显示区域
     * @param {*} changeType
     * @param {*} changeValueId
     */
    createMainContentHTML(changeType, changeValueId) {
        // 如果没有修改
        let 
            isNavTypeNotChange = changeType === 'nav' && changeValueId === this.shopInfoObj.selectedNavId,
            isSubNavTypeNotChange = changeType === 'subnav' && changeValueId === this.shopInfoObj.selectedSubNavId;
        if (isNavTypeNotChange || isSubNavTypeNotChange) {
            return;
        }

        let 
            selectedNavId,
            selectedSubNavId;
        if (!changeType) { // 初始化
            selectedNavId = this.shopInfoObj.selectedNavId = "10";
            selectedSubNavId = this.shopInfoObj.selectedSubNavId = "00";
        } else if (changeType === 'nav') { // 切换一级导航
            selectedNavId = this.shopInfoObj.selectedNavId = changeValueId;
            selectedSubNavId = this.shopInfoObj.selectedSubNavId = "00";
        } else if (changeType === 'subnav') { // 切换二级导航
            selectedNavId = this.shopInfoObj.selectedNavId;
            selectedSubNavId = this.shopInfoObj.selectedSubNavId = changeValueId;
        } else if (changeType === "refresh") {
            selectedNavId = this.shopInfoObj.selectedNavId;
            selectedSubNavId = this.shopInfoObj.selectedSubNavId;
        } else {
            throw new Error(`createMainContentHTML-> 参数传递出错，无法正确解析-> changeType: ${changeType} changeValueId: ${changeValueId}`);
        }

        if (!changeType) {
            // 获取分类列表
            let categoryObj = this.getMakerShopCategoryInfo();
            let _selectedClassId = this.shopInfoObj.selectedClassId;
            this.shopInfoObj.resNavSortObj = categoryObj[_selectedClassId];
        }

        let resNavSortObj = this.shopInfoObj.resNavSortObj;
        // 导航 nav
        let navKeysList = Object.keys(resNavSortObj);
        let 
            navKey,
            navItem,
            navName,
            navHTML = '';
        for (let i = 0; i < navKeysList.length; i++) {
            navKey = navKeysList[i];
            navItem = resNavSortObj[navKey];
            if (isNaN(Number(navKey))) { // 因为根据res_class解析的，所有id均为数字
                continue;
            }
            navName = 0 === langindex ? navItem.name_ch : navItem.name_en;
            navHTML += `
            <div class="nav-item${navKey === selectedNavId ? ' checked' : ''}" data-id="${navKey}">
                <span>${navName}</span>
                <img src="${navItem.icon}"/>
            </div>
            `;
        }
        this.popUpShopNavEle.innerHTML = navHTML;

        // 子导航 subnav
        let subNavResList = resNavSortObj[selectedNavId];
        let subNavKeysList = Object.keys(subNavResList);
        let 
            subNavKey,
            subNavItem,
            subNavName,
            subNavHTML = '';
        for (let i = 0; i < subNavKeysList.length; i++) {
            subNavKey = subNavKeysList[i];
            subNavItem = subNavResList[subNavKey];
            if (isNaN(Number(subNavKey))) { // 因为根据res_class解析的，所有id均为数字
                continue;
            }
            subNavName = 0 === langindex ? subNavItem.name_ch : subNavItem.name_en;
            subNavHTML += `
            <div class="sub-nav-item${selectedSubNavId === subNavKey ? ' checked' : ''}" data-id="${subNavKey}">${subNavName}</div>
            `;
        }
        this.popUpShopSubNavEle.innerHTML = subNavHTML;
        // 将内容部分清空，准备渲染新的内容
        this.popUpShopContentEle.innerHTML = "";
        this.changeShopResDetailHTML(); // 清空详细信息侧边栏

        new Promise((resolve, reject) => {
            // 目前只实现分类请求，分页请求以后实现
            // 先将导航切换过去，然后再进行网络请求

            // 查看该分类是不是已经进行过网络请求了
            if (this.shopInfoObj.resNavSortObj[selectedNavId][selectedSubNavId].pageList) {
                resolve();
                return;
            }

            // Loading
            let loaderEle = this.createElement("div");
                loaderEle.id = "loader";
                loaderEle.style.display = "flex";
                loaderEle.innerHTML = `
                    <div class="load-container load4">
                        <div class="loader">Loading...</div>
                    </div>
                `;
            this.popUpShopContentEle.appendChild(loaderEle);

            let options = {
                navId: Number(selectedNavId + "" + selectedSubNavId),
                pageSize: 100,
                pageNum: 1
            };
            this.getResourcesListFromServer(options, (devuid, pubResList) => {
                this.shopInfoObj.devuid = devuid;
                this.shopInfoObj.pubResList = pubResList;

                // 整理列表
                let 
                    resItem;
                for (let i = 0; i < pubResList.length; i++) {
                    resItem = pubResList[i];
                    try {
                        this.shopInfoObj.resNavSortObj[selectedNavId][selectedSubNavId].list.push(resItem);
                    } catch(e) {
                        console.error("整理资源商店数据时出错，错误信息如下: ");
                        console.error(e);
                        console.error(resItem);
                        console.error("----------------------------------------------------------------");
                        throw new Error("获取商店资源出错!");
                    }
                }
                this.shopInfoObj.resNavSortObj[selectedNavId][selectedSubNavId].pageList = [1];
                resolve();
            });
        }).then(() => {
            let loadingEle = document.getElementById("loader");
            loadingEle && loadingEle.remove();

            // 根据变量，显示核心内容区域
            let gameResList = subNavResList[selectedSubNavId].list;
            let devuid = this.shopInfoObj.devuid;
            // 右侧内容区域
            let rightContentItemHTML = '';
            let 
                length = gameResList.length,
                curItem,
                imageSrc,
                resFilePath,
                price,
                desc,
                tag,
                previewImg,
                viewsCount,
                downloadCount,
                createDate,
                updateDate,
                name,
                previewImgList;
            for (let i = 0; i < length; i++) {
                curItem = gameResList[i];
                resFilePath = curItem.res_file;
                price = curItem.res_price;
                desc = curItem.res_desc;
                tag = curItem.res_tag;
                previewImg = curItem.preview_img;
                viewsCount = curItem.views_count;
                downloadCount = curItem.download_count;
                createDate = curItem.created_at;
                updateDate = curItem.updated_at;
                name = curItem.res_filename;

                resFilePath = `${codeMain.layamakerFileURL}/${resFilePath}`;
                previewImgList = (previewImg && previewImg.split("|")) || [];
                if (this.shopType === "sound") { // 声音
                    rightContentItemHTML += `
                    <div class="content-item content-list-item ${this.shopType}" data-path="${resFilePath}" data-name="${name}" data-index="${i}">
                        <div class="btn-save"></div>
                        <div class="name">${name}</div>
                        <div class="auther">${'self'}</div>
                        <div class="resource-btn-list">
                            <div class="btn-hear"></div>
                            <div class="btn-use"></div>
                        </div>
                        <div class="buy">${price}</div>
                        <hr />
                    </div>
                    `;
                } else { // 非声音(有图片预览)
                    if (resFilePath.endsWith("zip")) { // 文件夹
                        // resources/app/out/vs/layaEditor/
                        let localIcon = `${codeMain.path.join(__dirname, "../", "../")}/h5/skins/default/icons/components/Box.png`;
                        if (!previewImgList[0]) {
                            imageSrc = localIcon;
                        } else {
                            imageSrc = `${codeMain.layamakerResURL}/${previewImgList[0]}`;
                        }
                    } else {
                        imageSrc = resFilePath;
                    }
                    rightContentItemHTML += `
                    <div class="content-item content-list-item common ${this.shopType}" data-path="${resFilePath}" data-name="${name}" data-index="${i}">
                        <div class="image-wrapper">
                            <img src="${imageSrc}"/>
                            <div class="btn-wrapper">
                                <div class="btn-use"></div>
                            </div>
                        </div>
                        <div class="info-wrapper">
                            <div class="name">${name}</div>
                            <div class="buy">${price}</div>
                        </div>
                    </div>
                    `;
                }
            }
            if (this.shopType === "ani" || this.shopType === "part") { // 动画、粒子，第一个是自定义item
                rightContentItemHTML = `
                <div class="content-item common ${this.shopType}" data-type="add">
                    <div class="image-wrapper" style="height: 100%;">
                        <img src="./skins/default/image/ide/res-shop-add.png"/>
                    </div>
                </div>
                ` + rightContentItemHTML;
            }
            this.popUpShopContentEle.innerHTML = rightContentItemHTML;

            // 显示第一个详细区域
            if (gameResList[0]) {
                let detailItem = gameResList[0];
                this.changeShopResDetailHTML(detailItem, 0);
            }
        }).catch((err) => {
            let loadingEle = document.getElementById("loader");
            loadingEle && loadingEle.remove();
            throw err;
        });
        return;
    }
    // 切换显示
    changeShopResDetailHTML(detailItem, index) {
        if (!detailItem || !(typeof detailItem === "object")) { // 传过来的不是对象
            this.popUpShopDetailEle.innerHTML = "";
            return;
        }
        let _isShowMyList = sessionStorage.getItem("isShowMyList") === "true";
        // 被点击的item，显示选中效果
        let oldSelectedEle = this.popUpShopContentEle.getElementsByClassName("selected")[0];
        if (oldSelectedEle) {
            oldSelectedEle.className = oldSelectedEle.className.replace(" selected", "");
        }
        let newSelectedEle = this.popUpShopContentEle.getElementsByClassName("content-list-item")[index];
        if (newSelectedEle) {
            newSelectedEle.className += " selected";
        }
        let 
            resId = detailItem.res_id,
            resFilePath = detailItem.res_file,
            price = detailItem.res_price,
            desc = detailItem.res_desc || "",
            tag = detailItem.res_tag || "",
            previewImg = detailItem.preview_img,
            viewsCount = detailItem.views_count || 0,
            downloadCount = detailItem.download_count || 0,
            createDate = detailItem.created_at,
            updateDate = detailItem.updated_at,
            name = detailItem.res_filename,
            previewImgList = (previewImg && previewImg.split("|")) || [],
            auditStatus = detailItem.audit_status,
            classId = detailItem.res_class,
            navId = detailItem.res_nav,
            res_extends = detailItem.res_extends;
        let previewHTML = '';
        for (let i = 0; i < previewImgList.length; i++) {
            previewHTML += `
                <div class="shop-detail-image-contain">
                    <img src="${codeMain.layamakerResURL}/${previewImgList[i]}" class="shop-detail-image"/>
                </div>
            `;
        }
        // 审核状态
        let auditText;
        switch(auditStatus) {
            case -1: // 下线
                auditText = codeMain.getPanelLang(413);
                break;
            case 0: // 未发布
                auditText = codeMain.getPanelLang(414);
                break;
            case 1: // 已发布
                auditText = codeMain.getPanelLang(415);
                break;
            case 2: // 通过审核
                auditText = codeMain.getPanelLang(416);
                break;
            case 3: // 审核拒绝
                auditText = codeMain.getPanelLang(417);
                break;
            default: // 请于服务提供商联系
                auditText = codeMain.getPanelLang(418);
        }
        let 
            navSelectHTML,
            subNavSelectHTML;
        if (_isShowMyList) {
            // 获取导航-子导航
            let navObj = this.getNavSelectHTML(navId);
            // this.shopInfoObj.uploadClassId = navObj._selectedClassId;
            this.shopInfoObj.uploadNavSelectListObj = navObj.navObjListObj;
            navSelectHTML = navObj.navSelectHTML,
            subNavSelectHTML = navObj.subNavSelectHTML;
        }
        
        let inputStyle = 'position: static; display: inline-block; width: 180px; height: 10px;';
        this.popUpShopDetailEle.setAttribute("data-resid", resId);
        this.popUpShopDetailEle.setAttribute("data-classId", classId);
        this.popUpShopDetailEle.setAttribute("data-navId", navId);
        this.popUpShopDetailEle.setAttribute("data-index", index);
        this.popUpShopDetailEle.setAttribute("data-auditstatus", auditStatus);
        this.popUpShopDetailEle.innerHTML = `
            <!-- 名称 -->
            <div class="shop-detail-name">
                <span class="shop-item-label">${codeMain.getPanelLang(336)}:</span>
                ${!_isShowMyList ? 
                    `<span class="shop-item-info">${name}</span>` : 
                    `<input class="common-skins-input shop-detail-name-input" type="text" data-value="${name}" value="${name}" style="${inputStyle}">`
                }
            </div>
            <!-- 描述 -->
            <div class="shop-detail-desc">
                <span class="shop-item-label">${codeMain.getPanelLang(337)}:</span>
                ${!_isShowMyList ? 
                    `<span class="shop-item-info">${desc}</span>` : 
                    `<input class="common-skins-input shop-detail-desc-input" type="text" data-value="${desc}" value="${desc}" style="${inputStyle}">`
                }
            </div>
            <!-- 价格 -->
            <div class="shop-detail-item">
                <span class="shop-item-label">${codeMain.getPanelLang(339)}:</span>
                ${!_isShowMyList ? 
                    `<span class="shop-item-info">${price}</span>` : 
                    `<input class="common-skins-input shop-detail-price-input" type="text" data-value="${price}" value="${price}" style="${inputStyle}">`
                }
            </div>
            <!-- 标签 -->
            <div class="shop-detail-item">
                <span class="shop-item-label">${codeMain.getPanelLang(338)}:</span>
                ${!_isShowMyList ? 
                    `<span class="shop-item-info">${tag}</span>` : 
                    `<input class="common-skins-input shop-detail-tag-input" type="text" data-value="${tag}" value="${tag}" style="${inputStyle}">`
                }
            </div>
            <!-- 类别 -->
            <div class="shop-detail-item mylist-show">
                <span class="shop-item-label">${codeMain.getPanelLang(340)}:</span>
                <div style="display: inline-block;">
                    <select id="navSelect">
                        ${navSelectHTML}
                    </select>
                    <select id="subNavSelect">
                        ${subNavSelectHTML}
                    </select>
                </div>
            </div>
            <!-- 审核状态 -->
            <div class="shop-detail-item mylist-show">
                <span class="shop-item-label">${codeMain.getPanelLang(412)}:</span>
                <span class="shop-item-info">${auditText}</span>
            </div>
            <!-- 浏览次数 -->
            <div class="shop-detail-item">
                <span class="shop-item-label">${codeMain.getPanelLang(408)}:</span>
                <span class="shop-item-info">${viewsCount}</span>
            </div>
            <!-- 下载次数 -->
            <div class="shop-detail-item">
                <span class="shop-item-label">${codeMain.getPanelLang(409)}:</span>
                <span class="shop-item-info">${downloadCount}</span>
            </div>
            <!-- 创建时间 -->
            <div class="shop-detail-item">
                <span class="shop-item-label">${codeMain.getPanelLang(410)}:</span>
                <span class="shop-item-info">${createDate}</span>
            </div>
            <!-- 更新时间 -->
            <div class="shop-detail-item">
                <span class="shop-item-label">${codeMain.getPanelLang(411)}:</span>
                <span class="shop-item-info">${updateDate}</span>
            </div>
            <!-- 附加信息 -->
            ${_isShowMyList ? 
                `
                    <div class="shop-detail-item">
                        <span class="shop-item-label">附加信息:</span>
                        <span class="shop-item-info" data-value="${res_extends}">${res_extends}</span>
                    </div>
                ` : ``
            }
            <!-- 资源地址 -->
            ${_isShowMyList ? 
                `
                    <div class="shop-detail-item">
                        <span class="shop-item-label">资源地址:</span>
                        <span class="shop-item-info upload-file-link" data-value="${resFilePath}" style="cursor: pointer;">${resFilePath}</span>
                    </div>
                ` : ``
            }
            <!-- 更新预览图 -->
            ${_isShowMyList ? 
                `
                    <div class="shop-detail-item">
                        <span class="shop-item-label">预览图:</span>
                        <span class="shop-item-info upload-preview-image-link"  data-value="${previewImg}" style="cursor: pointer;">${previewImg}</span>
                    </div>
                ` : ``
            }
            <!-- 预览图 -->
            <div class="shop-detail-preview-wrapper">
                ${previewHTML}
            </div>
            <!-- 下线 -->
            ${_isShowMyList && auditStatus >= 1 ? 
                `
                <button class="common-skins-downline-btn layaBtnCustum" style="bottom: 150px; left: 106px;">
                    下线
                </button>
                ` : ``
            }
            <!-- 修改/使用 -->
            <button class="common-skins-ok-btn" style="bottom: 80px; left: 106px;">
                ${_isShowMyList ? codeMain.getPanelLang(420) : codeMain.getPanelLang(419)}
            </button>
        `;
        // 修改类别
        if (_isShowMyList) {
            document.getElementById("navSelect").addEventListener("change", this.handleNavSelectChange.bind(this), false);
        }
    }
    getServerStorageName(fileName) {
        let name = fileName && codeMain.path.basename(fileName);
        // if (this.isDirType()) {
        //     name = fileName && codeMain.path.basename(codeMain.path.dirname(fileName));
        // }
        return name;
    }
    /**
     * 返回上传的是否是文件件
     * - 仅当有该类型，并且isSingleFile为false时返回true
     * - 1) isSingleFile为true时 2) 没有改shopType时，返回false
     */
    isDirType() {
        let singleTypeInfo = this.makerInfoObj[this.shopType];
        return !!(singleTypeInfo && !singleTypeInfo.isSingleFile);
    }
    destoryPopUpShopHTML() {
        if (!this.isPopUpShopShow()) {
            return;
        }
        this.popUpShopEle.innerHTML = '';
        this.popUpShopEle.style = '';
        this.popUpShopEle = null;
        this.popUpShopWebViewEle = null;
    }
    isPopUpShopShow() {
        return !!this.popUpShopEle;
    }
    // 商店，共同函数
    checkShopCanShow() { // 初始化检查
        // 判断是否登录，如果没有登录，return
        if (window.globalMode !== codeMain.globalModeType.layamaker) {
            alert("IDE不处于layamaker模式");
            return false;
        }
        if (!this.isLogin()) {
            alert('请先登录');
            return false;
        }
        return true;
    }
    bindShopEventListener() {
        // 右侧栏
        // 一二级导航、使用
        this.popUpShopMainEle.addEventListener('click', () => {
            let _isShowMyList = sessionStorage.getItem("isShowMyList") === "true";
            let target = event.target;
            let parentNodeEle = target;
            let 
                isUse,
                isPlayAudio;
            for (let i = 0; i < 10; i++) {
                if (!parentNodeEle) { // 没有父元素了，return
                    return;
                }
                let className = parentNodeEle.className;
                if (typeof className !== "string") {
                    return;
                }
                if (className.indexOf('shop-content-wrapper') !== -1) {
                    return;
                }
                if (className === 'nav-item') { // 一级导航
                    let typeId = parentNodeEle.getAttribute('data-id');
                    this.createMainContentHTML('nav', typeId);
                    return;
                }
                if (className === 'sub-nav-item') { // 二级导航
                    let typeId = parentNodeEle.getAttribute('data-id');
                    this.createMainContentHTML('subnav', typeId);
                    return;
                }
                if (className.indexOf('content-item') !== -1 && parentNodeEle.getAttribute("data-type") === "add") { // 动画、粒子，第一个是自定义item
                    laya.editor.view.cloud.CloudResourceManager.I.addNewFile(this.shopType);
                    this.destoryPopUpShopHTML();
                    return;
                }
                if (className.indexOf('content-item') !== -1) { // 获取需要的data
                    let 
                        path = parentNodeEle.getAttribute('data-path'),
                        index = parentNodeEle.getAttribute('data-index'),
                        resName = parentNodeEle.getAttribute("data-name");
                    let gameResList;
                    try {
                        gameResList = this.shopInfoObj.resNavSortObj[this.shopInfoObj.selectedNavId][this.shopInfoObj.selectedSubNavId].list;
                    } catch(e) {}
                    if (!Array.isArray(gameResList)) {
                        gameResList = [];
                    }
                    this.changeShopResDetailHTML(gameResList[index], index); // 显示对应的详情信息
                    if (isUse) { // 使用
                        // Loading
                        let loaderEle = this.createElement("div");
                        loaderEle.id = "loader";
                        loaderEle.style.display = "flex";
                        loaderEle.innerHTML = `
                            <div class="load-container load4">
                                <div class="loader">Loading...</div>
                            </div>
                        `;
                        this.popUpShopMainEle.appendChild(loaderEle);
                        let tempPath = codeMain.path.join(remote.app.getPath("userData"), "cloudRes");
                        let resPathName = this.getServerStorageName(path); // 资源名称，hash
                        let extName = codeMain.path.extname(resPathName); // 后缀名
                        let hashName = resPathName.replace(extName, ""); // 供解压使用
                        // 声音、图片的使用
                        if (!this.isDirType()) { // 声音，图片
                            let fullPath = codeMain.path.join(tempPath, resPathName); // 传过去的路径，要包括名字和后缀名
                            codeMain.tool.downFileToDir(path, fullPath).then(() => {
                                let params = {
                                    path: fullPath,
                                    name: resName,
                                    type: this.shopType
                                }
                                laya.editor.view.cloud.CloudResourceManager.I.addRemoteRes(params);
                                document.getElementById("loader").remove();
                            });
                            return;
                        }
                        tempPath = codeMain.path.join(tempPath, hashName); // 每个文件解压到对应的文件夹中
                        codeMain.tool.downAndExtractZip(path, tempPath).then(() => {
                            let params = {
                                path: tempPath,
                                name: resName,
                                type: this.shopType
                            }
                            laya.editor.view.cloud.CloudResourceManager.I.addRemoteRes(params);
                            document.getElementById("loader").remove();
                        });
                        return;
                    } else if (isPlayAudio) { // 声音，试听
                        this.playAudio(parentNodeEle);
                        return;
                    }
                }
                if (className.indexOf('btn-use') !== -1) { // 使用
                    isUse = true;
                }
                if (className.indexOf("btn-hear") !== -1) { // 声音，试听
                    isPlayAudio = true;
                }
                if (className.indexOf("common-skins-ok-btn") !== -1) { // 详情部分的 使用/修改 按钮
                    if (_isShowMyList) {
                        this.modifyResInfo();
                    } else {
                        let selectedEle = this.popUpShopMainEle.getElementsByClassName("shop-content-wrapper")[0].getElementsByClassName("selected")[0];
                        selectedEle.getElementsByClassName("btn-use")[0].click();
                    }
                    return;
                }
                if (className.indexOf("common-skins-downline-btn") !== -1) { // 详情panel，下线按钮
                    this.downLine();
                    return;
                }
                if (className.indexOf("upload-file-link") !== -1 && _isShowMyList) { // 详情panel，修改资源，替换为本地地址
                    this.resourcesBtnClickHanler(parentNodeEle);
                    return;
                }
                if (className.indexOf("upload-preview-image-link") !== -1 && _isShowMyList) { // 详情panel，修改预览图，替换为本地地址
                    let _parentNodeEle = parentNodeEle;
                    codeMain.remote.dialog.showOpenDialog({
                        properties: ["openFile", "multiSelections"],
                        filters: [{name: 'image', extensions: this.makerInfoObj["pic"].extensionList}],
                    }, function(p) {
                        if (p) {
                            let length = p.length > 4 ? 4 : p.length;
                            _parentNodeEle.innerHTML = '';
                            for (let i = 0; i < length; i++) {
                                _parentNodeEle.innerHTML += p[i] + ';';
                            }
                        }
                    });
                    return;
                }
                parentNodeEle = parentNodeEle.parentNode;
            }
        }, false);
        // 关闭按钮
        this.popUpShopMainAreaEle.getElementsByClassName("common-tool-close")[0].addEventListener("click", () => {
            this.destoryPopUpShopHTML();
        }, false);
    }

    playAudio(oprationEle) {
        let audioEle = document.getElementById("res_audio");
        let path = oprationEle.getAttribute("data-path");
        let _this = this;
        if (!audioEle) {
            // 没有音频播放
            initAudio(path);
        } else if (audioEle) {
            // 两种情况，停止音频的播放，或者播放另一个音频
            let 
                playingSrc = audioEle.src,
                isPaused = audioEle.paused,
                isEnded = audioEle.ended;
            if (playingSrc === path && !isPaused && !isEnded) { // 同一个音频，没有被停止，没有播放完毕 -> 暂停
                stopAudio();
            } else if (playingSrc === path && (isPaused || isEnded)) { // 同一个音频，停止或者播放完毕 -> 播放
                rePlayAudio();
            } else if (playingSrc !== path) { // 不同的音频
                initAudio(path);
            }
        }

        // 功能实现
        function initAudio(audioSrc) {
            if (!audioEle) {
                audioEle = document.createElement("AUDIO");
                audioEle.id = "res_audio";
                _this.popUpShopMainEle.appendChild(audioEle);
            }
            audioEle.onerror = function(e) {
                console.error(e);
            }
            audioEle.autoplay = true;
            audioEle.controls = true;
            audioEle.src = audioSrc;
        }

        function stopAudio() {
            audioEle.pause();
        }

        function rePlayAudio() {
            audioEle.play();
        }
    }

    // 获取资源列表
    // 获取某项资源的全部列表
    getResourcesListFromServer(options, func) {
        // options
        this.getLayaMakerToken((token, devuid) => {
            let
                pubResList; // 账户无关公共资源
            // 请求公共资源列表
            let publicURL = `${codeMain.layamakerAPPURL}/index`; // 请求资源列表
            let fd2 = new FormData();
            fd2.append("access_token", token);
            let _isShowMyList = sessionStorage.getItem("isShowMyList") === "true";
            if (_isShowMyList) {
                fd2.append("act", "showmylist");
            } else {
                fd2.append("act", "showlist");
            }
            fd2.append("res_class", Number(this.shopInfoObj.selectedClassId));
            fd2.append("res_nav", options.navId);
            fd2.append("pagesize", options.pageSize);
            fd2.append("page", options.pageNum);
            fd2.append("config_name", "res_cloud");
            let serverResParams = {
                url: publicURL,
                content: fd2
            };
            codeMain.postInfoToServer(serverResParams, (responseText) => {
                try {
                    pubResList = JSON.parse(responseText).data;
                } catch(e) {
                    pubResList = [];
                }
                if (!Array.isArray(pubResList)) {
                    pubResList = [];
                }
                func instanceof Function && func(devuid, pubResList);
            });
        });
    }

    /**
     * 上传资源panel
     * 目前只能命令行调用
     */
    createUploadPanel(type) {
        console.log(`%c codeMain.layaPageIns.createUploadPanel("${type}")`, "color: green;");
        let isPass = this.checkShopCanShow();
        if (!isPass) {
            return;
        }
        const TYPE_TEXT = this.makerInfoObj;
        if (type && TYPE_TEXT[type] instanceof Object) { // 如果传过来的值不能够正常解析，则默认显示上传图片
            this.shopType = type;
        } else {
            this.shopType = 'pic';
        }

        let navObj = this.getNavSelectHTML();
        this.shopInfoObj.uploadClassId = navObj._selectedClassId;
        this.shopInfoObj.uploadNavSelectListObj = navObj.navObjListObj;
        let 
            navSelectHTML = navObj.navSelectHTML,
            subNavSelectHTML = navObj.subNavSelectHTML;
        const 
            INPUT_LEFT = 80,
            INPUT_WIDTH = 380,
            BTN_LEFT = 477;
        const 
            COMMON_SPAN_STYLE = "position: absolute; width: 65px; left: 10px; text-align: right;";
        this.uploadPopUpEle = this.createElement("div");
        this.uploadPopUpEle.id = "upload-panel-wrapper";

        this.uploadPopUpEle.innerHTML = `
            <div class="upload-wrapper-content">
                <div class="common-tool-title">
                    <div class="common-tool-icon-wrapper">
                        <img class="common-tool-icon" title="${TYPE_TEXT[this.shopType].title}" src="skins/default/image/ide/layamaker-newpro.png" style="width: 18px; height: 20px;">
                    </div>
                    <div class="common-tool-title-content">${TYPE_TEXT[this.shopType].title}</div>
                    <div class="common-tool-close"></div>
                </div>
                <div class="upload-mian-area">
                    <!-- 资源路径 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 100px;">${codeMain.getPanelLang(342)}</span>
                    <input class="common-skins-input upload-file-input" type="text" placeholder="${codeMain.getPanelLang(342)}" style="left: ${INPUT_LEFT}px; width: ${INPUT_WIDTH}px; top: 100px;" readonly="readonly"/>
                    <button class="common-skins-file-btn upload-file-btn" type="text" style="top: 100px; left: ${BTN_LEFT}px;">${codeMain.getPanelLang(22)}</button>
                    <!-- 预览图 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 150px;">${codeMain.getPanelLang(341)}</span>
                    <input class="common-skins-input upload-previmage-input" type="text" placeholder="${codeMain.getPanelLang(341)}" style="left: ${INPUT_LEFT}px; width: ${INPUT_WIDTH}px; top: 150px;" readonly="readonly"/>
                    <button class="common-skins-file-btn upload-preview-image-btn" type="text" style="top: 150px; left: ${BTN_LEFT}px;">${codeMain.getPanelLang(22)}</button>
                    <!-- 名称 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 200px;">${codeMain.getPanelLang(336)}</span>
                    <input class="common-skins-input upload-name-input" type="text" placeholder="${codeMain.getPanelLang(336)}" style="left: ${INPUT_LEFT}px; width: ${INPUT_WIDTH}px; top: 200px;"/>
                    <!-- 描述 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 250px;">${codeMain.getPanelLang(337)}</span>
                    <input class="common-skins-input upload-des-input" type="text" placeholder="${codeMain.getPanelLang(337)}(0-255)" style="left: ${INPUT_LEFT}px; width: ${INPUT_WIDTH}px; top: 250px;"/>
                    <!-- 标签 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 300px;">${codeMain.getPanelLang(338)}</span>
                    <input class="common-skins-input upload-tag-input" type="text" placeholder="${codeMain.getPanelLang(338)}(0-120)" style="left: ${INPUT_LEFT}px; width: ${INPUT_WIDTH}px; top: 300px;"/>
                    <!-- 价格 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 350px;">${codeMain.getPanelLang(339)}</span>
                    <input class="common-skins-input upload-price-input" type="text" placeholder="${codeMain.getPanelLang(339)}(1-30)" style="left: ${INPUT_LEFT}px; width: ${INPUT_WIDTH}px; top: 350px;"/>
                    <!-- 类别 -->
                    <span class="common-inputbefore-label" style="${COMMON_SPAN_STYLE} top: 400px;">${codeMain.getPanelLang(340)}</span>
                    <div style="position: absolute; left: ${INPUT_LEFT}px; top: 400px;">
                        <select id="navSelect">
                            ${navSelectHTML}
                        </select>
                        <select id="subNavSelect">
                            ${subNavSelectHTML}
                        </select>
                    </div>
                    <!-- 上传多个文件 -->
                    ${
                        this.isDirType() ? `
                            <label style="position: absolute; left: 80px; top: 435px; height: 20px; display: flex; justify-content: center; align-items: center; font-size: 14px;">
                                <input class="multiUpload" type="checkbox">&nbsp;&nbsp;<span>是否上传多个文件</span>
                            </label>
                        ` : ``
                    }
                    <!-- 确定按钮 -->
                    <button class="common-skins-ok-btn" style="top: 500px; left: 206px;">${codeMain.getPanelLang(38)}</button>
                </div>
            </div>
        `;
        codeMain.addPopLayer(this.uploadPopUpEle);

        let 
            title = this.uploadPopUpEle.getElementsByClassName("common-tool-title")[0];
        __Layadrag(this.uploadPopUpEle, title);
        this.bindMakerUploadEvent();
    }

    /**
     * 获取当前类型下分类列表HTML和Obj
     * - HTML 为 options-select
     */
    getNavSelectHTML(resNavId) {
        resNavId = resNavId ? (resNavId + "") : "";
        let 
            navId = resNavId.substr(0, 2),
            subNavId = resNavId.substr(2, 2);
        // 获取分类列表对象
        let categoryObj = this.getMakerShopCategoryInfo();
        let _selectedClassId = this.makerInfoObj[this.shopType]._classId;
        let resNavObj = categoryObj[_selectedClassId];
        // 确定类别，定制选择框
        let navKeysList = Object.keys(resNavObj);
        let 
            navObjListObj = {},
            navItemObj;
        let navSelectHTML = ``;
        let 
            navKey,
            navItem,
            navName,
            selectedNavKey;
        for (let i = 0; i < navKeysList.length; i++) {
            navKey = navKeysList[i];
            navItem = resNavObj[navKey];
            if (isNaN(Number(navKey))) { // 因为根据res_class解析的，所有id均为数字
                continue;
            }
            navName = 0 === langindex ? navItem.name_ch : navItem.name_en;
            navItemObj = {
                name: navName,
                id: navItem._id,
                list: []
            };
            if ((navId && Number(navItem._id) === Number(navId)) || (!navId && i === 0)) {
                selectedNavKey = navKey;
                navSelectHTML += `<option value="${navItem._id}" selected="selected">${navName}</option>`;
            } else {
                navSelectHTML += `<option value="${navItem._id}">${navName}</option>`;
            }
            // 整理子导航项
            let subNavResList = resNavObj[navItem._id];
            let subNavKeysList = Object.keys(subNavResList);
            let 
                subNavKey,
                subNavItem,
                subNavName;
            for (let j = 0; j < subNavKeysList.length; j++) {
                subNavKey = subNavKeysList[j];
                subNavItem = subNavResList[subNavKey];
                if (isNaN(Number(subNavKey))) { // 因为根据res_class解析的，所有id均为数字
                    continue;
                }
                subNavName = 0 === langindex ? subNavItem.name_ch : subNavItem.name_en;
                navItemObj.list.push({
                    name: subNavName,
                    id: subNavItem._id
                });
            }
            navObjListObj[navKey] = navItemObj;
        }
        // 确定默认的子导航的数组
        let 
            subList = navObjListObj[selectedNavKey].list,
            subItem,
            subNavSelectHTML = ``;
        for (let i = 0; i < subList.length; i++) {
            subItem = subList[i];
            if ((subNavId && Number(subItem.id) === Number(subNavId)) || (!subNavId && i === 0)) {
                subNavSelectHTML += `<option value="${subItem.id}" selected="selected">${subItem.name}</option>`;
            } else {
                subNavSelectHTML += `<option value="${subItem.id}">${subItem.name}</option>`;
            }
        }
        return {
            navSelectHTML,
            subNavSelectHTML,
            navObjListObj,
            _selectedClassId
        }
    }

    /**
     * 获取maker商店分类信息
     */
    getMakerShopCategoryInfo() {
        let categoryPath = codeMain.path.join(__dirname, "../", "config", "shopcategory.json");
        let categoryObj = codeMain.fs.readFileSync(categoryPath, "utf8");
        categoryObj = JSON.parse(categoryObj);
        return categoryObj;
    }


    /**
     * 切换主分类，子分类跟着变动
     * - 调用时注意绑定this
     */
    handleNavSelectChange(e) {
        let id = e.target.value;
        let navObjListObj = this.shopInfoObj.uploadNavSelectListObj;
        let 
            subList = navObjListObj[id].list,
            subItem,
            subNavSelectHTML = ``;
        for (let i = 0; i < subList.length; i++) {
            subItem = subList[i];
            subNavSelectHTML += `<option value="${subItem.id}">${subItem.name}</option>`;
        }
        document.getElementById("subNavSelect").innerHTML = subNavSelectHTML;
    }

    bindMakerUploadEvent() {
        let 
            fileInput = this.uploadPopUpEle.getElementsByClassName("upload-file-input")[0],
            nameInput = this.uploadPopUpEle.getElementsByClassName("upload-name-input")[0],
            // desInput = this.uploadPopUpEle.getElementsByClassName("upload-des-input")[0],
            // priceInput = this.uploadPopUpEle.getElementsByClassName("upload-price-input")[0],
            // tagInput = this.uploadPopUpEle.getElementsByClassName("upload-tag-input")[0],
            previmageInput = this.uploadPopUpEle.getElementsByClassName("upload-previmage-input")[0];
        this.uploadPopUpEle.addEventListener('click', () => {
            let target = event.target;
            let parentNodeEle = target;
            for (let i = 0; i < 10; i++) {
                if (!parentNodeEle) { // 没有父元素了，return
                    return;
                }
                let className = parentNodeEle.className;
                if (typeof className !== "string") {
                    return;
                }
                if (className.indexOf('upload-wrapper-content') !== -1) {
                    return;
                }
                if (className == 'common-skins-ok-btn') { // 确定
                    this.uploadFileToServer();
                    return;
                } else if (className.includes("upload-file-btn") || className.includes("upload-file-input")) { // 资源btn
                    this.resourcesBtnClickHanler(fileInput, nameInput);
                } else if (className.includes("upload-preview-image-btn") || className.includes("upload-previmage-input")) { // 预览图btn
                    codeMain.remote.dialog.showOpenDialog({
                        properties: ["openFile", "multiSelections"],
                        filters: [{name: 'image', extensions: this.makerInfoObj["pic"].extensionList}],
                        defaultPath: previmageInput.value
                    }, function(p) {
                        if (p) {
                            let length = p.length > 4 ? 4 : p.length;
                            previmageInput.value = '';
                            for (let i = 0; i < length; i++) {
                                previmageInput.value += p[i] + ';';
                            }
                        }
                    });
                }
                parentNodeEle = parentNodeEle.parentNode;
            }
        }, false);
        // 修改类别
        document.getElementById("navSelect").addEventListener("change", this.handleNavSelectChange.bind(this), false);
        // 处理拖动事件
        this.uploadPopUpEle.ondrop = this.handleDropFileToFileInput.bind(this);
        // 关闭按钮
        this.uploadPopUpEle.getElementsByClassName("common-tool-close")[0].addEventListener("click", () => {
            codeMain.removePopLayer(this.uploadPopUpEle);
        }, false);
    }

    /**
     * 上传文件，上传panel确定按钮调用事件
     * - 修改接口需要注意，上传资源涉及两部分，一部分为上传资源(即该函数)，一部分为修改资源(modifyResInfo())
     */
    uploadFileToServer() {
        let 
            fileInput = this.uploadPopUpEle.getElementsByClassName("upload-file-input")[0],
            nameInput = this.uploadPopUpEle.getElementsByClassName("upload-name-input")[0],
            desInput = this.uploadPopUpEle.getElementsByClassName("upload-des-input")[0],
            priceInput = this.uploadPopUpEle.getElementsByClassName("upload-price-input")[0],
            tagInput = this.uploadPopUpEle.getElementsByClassName("upload-tag-input")[0],
            previmageInput = this.uploadPopUpEle.getElementsByClassName("upload-previmage-input")[0],
            navSelectEle = document.getElementById("navSelect"),
            subNavSelectEle = document.getElementById("subNavSelect");
        let 
            desValue = desInput.value,
            classValue = this.shopInfoObj.uploadClassId,
            navValue = navSelectEle.value + subNavSelectEle.value,
            priceValue = priceInput.value,
            tagValue = tagInput.value;
        let isMultiUploadEle = this.uploadPopUpEle.getElementsByClassName("multiUpload")[0],
            isMultiUpload = !!(isMultiUploadEle && isMultiUploadEle.checked);
        let isUploadDir = this.isDirType();
        let _this = this;
        // 判断是否必填的字段都填写了
        let fileValue = fileInput.value;
        if (!fileValue) {
            alert(codeMain.getPanelLang(346)); // 请选择资源目录
            return;
        }
        if (!codeMain.fs.existsSync(fileValue)) {
            alert(codeMain.getPanelLang(347)); // 资源文件(夹)不存在
            return;
        }
        if (isUploadDir && codeMain.fs.readdirSync(fileValue).length == 0) {
            alert(codeMain.getPanelLang(348)); // 资源文件夹不能为空
            return;
        }
        let previewImageValue = previmageInput.value;
        if (isUploadDir && !previewImageValue) {
            alert(codeMain.getPanelLang(349)); // 预览图不能为空
            return;
        }
        if (desValue.length > 255) { // string: 0-255
            alert(codeMain.getPanelLang(350)); // 描述需要为10-255位的字符串
            return;
        }
        if (!navValue || navValue.length > 4 || isNaN(Number(navValue))) { // int: 1-4
            alert(codeMain.getPanelLang(351)); // 类别需要为1-4位的数字
            return;
        }
        if (!priceValue || priceValue.length > 30) { // string: 1-30
            alert(codeMain.getPanelLang(352)); // 价格需要为1-30位的字符串
            return;
        }
        if (!codeMain.tool.isMoney(priceValue)) {
            alert(codeMain.getPanelLang(378)); // 无法正确解析价格
            return;
        }
        if (tagValue.length > 120) { // string: 0-120
            alert(codeMain.getPanelLang(353)); // 标签需要为0-120位的字符串
            return;
        }

        // loading
        let loaderEle = this.createElement("div");
        loaderEle.id = "loader";
        loaderEle.style.display = "flex";
        loaderEle.innerHTML = `
            <div class="load-container load4">
                <div class="loader">Loading...</div>
            </div>
        `;
        this.uploadPopUpEle.getElementsByClassName("upload-wrapper-content")[0].appendChild(loaderEle);

        // 如果没有写name
        if (!nameInput.value) {
            nameInput.value = codeMain.path.basename(fileInput.value);
        }
        let fileNameValue = nameInput.value;

        // 1) 处理声音、图片文件夹的情况
        if (!isUploadDir) { // 声音、图片，上传文件夹
            let r = fs.lstatSync(fileValue);
            if (r.isDirectory()) {
                uploadMultiFile(fileValue, previewImageValue);
                return;
            }
        }
        // 2) 处理其他上传多个文件夹的情况
        if (isUploadDir && isMultiUpload) {
            uploadMultiDir(fileValue);
            return;
        }

        // 3) 处理上传单个文件的情况，包括声音、图片、文件夹
        let fd = new FormData();
        let params = {
            fd: fd,
            fileValue: fileValue,
            previewImageValue: previewImageValue
        };
        this.checkFileAndGetBinary(params).then((fd) => {
            convertFileToServer(fd);
        }).catch((msg) => {
            if (msg) {
                alert(msg);
            }
            let loaderEle = document.getElementById("loader");
            loaderEle.remove();
        });
        
        // 先请求到资源ID，然后再上传资源
        // 声音、图片批量上传的时候，会有func回调
        function convertFileToServer(_fd, filePath, func) {
            // 分为两步
            new Promise((resolve, reject) => {
                // 请求资源ID
                _this.getLayaMakerToken((token, devuid) => {
                    let uploadResURL = `${codeMain.layamakerAPPURL}/index`; // 上传资源
                    let fd2 = new FormData();
                    fd2.append("access_token", token);
                    fd2.append("act", "add");
                    fd2.append("config_name", "res_cloud");
                    fd2.append("res_price", priceValue); // string: 1-30
                    let 
                        _fileNameValue = fileNameValue,
                        _extName;
                    if (func instanceof Function) {
                        _extName = codeMain.path.extname(filePath);
                        _fileNameValue = codeMain.path.basename(filePath, _extName);
                    }
                    fd2.append("res_filename", _fileNameValue); // string: 1-30
                    fd2.append("res_desc", desValue); // string: 10-255
                    fd2.append("res_class", Number(classValue)); // int: 1-2
                    fd2.append("res_nav", Number(navValue)); // int: 1-4
                    fd2.append("res_tag", tagValue); // string: 2-120
                    fd2.append("developer_uid", devuid);
                    let serverResParams = {
                        url: uploadResURL,
                        content: fd2
                    };
                    codeMain.postInfoToServer(serverResParams).then((responseText) => {
                        let _infoObj2;
                        try {
                            _infoObj2 = responseText && JSON.parse(responseText);
                        } catch(e) {
                            _infoObj2 = null;
                        }

                        // 失败
                        if (!_infoObj2 || 'object' !== typeof _infoObj2 || _infoObj2.ret !== 0 || !_infoObj2.data.res_id) {
                            let errMsg = `re=${JSON.stringify(_infoObj2)}`;
                            throw new Error(errMsg);
                        }
                        // 成功
                        resolve({
                            resId: _infoObj2.data.res_id, 
                            resName: _fileNameValue
                        });
                    }).catch((e) => {
                        reject();
                        if (func instanceof Function) {
                            console.log(`${codeMain.getPanelLang(280)}: ${e}`);
                            func(false);
                        } else {
                            alert(`${codeMain.getPanelLang(280)}: ${e}`);
                            document.getElementById("loader").remove();
                        }
                        throw e;
                    });
                });
            }).then(({resId, resName}) => {
                // 上传资源(更新资源接口)
                _this.getLayaMakerToken((token, devuid) => {
                    let uploadResURL = `${codeMain.layamakerAPPURL}/index`; // 上传资源
                    _fd.append("access_token", token);
                    _fd.append("act", "update");
                    _fd.append("config_name", "res_cloud");
                    _fd.append("publish", 1); // 提交审核，这时资源已经就位了
                    _fd.append("res_id", Number(resId));
                    let serverResParams = {
                        url: uploadResURL,
                        content: _fd
                    };
                    codeMain.postInfoToServer(serverResParams).then((responseText) => {
                        let _infoObj2;
                        try {
                            _infoObj2 = responseText && JSON.parse(responseText);
                        } catch(e) {
                            _infoObj2 = null;
                        }
                        // if (isUploadDir) { // 如果是上传的zip包，该zip包是程序生成的，程序是否应该删除
                        //     codeMain.fs.unlink(filePath);
                        // }
                        
                        // 失败
                        if (!_infoObj2 || 'object' !== typeof _infoObj2 || _infoObj2.ret !== 0) {
                            let errMsg = `re=${JSON.stringify(_infoObj2)}`;
                            throw new Error(errMsg);
                        }
                        // 成功
                        console.log(`%c资源id: ${resId},资源名: ${resName} success`, "color: green;");
                        if (func instanceof Function) {
                            func(true, resId);
                        } else {
                            alert("上传成功");
                            document.getElementById("loader").remove();
                        }
                    }).catch((e) => {
                        console.log(`%c资源id: ${resId},资源名: ${resName} error`, "color: red;");
                        console.log(`codeMain.layaPageIns.createPopUpShopHTML("${_this.shopType}", true) 使用该函数重新上传资源`);
                        if (func instanceof Function) {
                            console.log(`${codeMain.getPanelLang(280)}: ${e}`);
                            func(false, resId);
                        } else {
                            alert(`${codeMain.getPanelLang(280)}: ${e}`);
                            document.getElementById("loader").remove();
                        }
                        throw e;
                    });
                });
            });
        }

        // 一次上传一整个文件夹的文件(音频、图片、字体)
        function uploadMultiFile(dirValue, previewImageValue) {
            let fileList = [];
            codeMain.getAllFileInFolder(dirValue, fileList);
            let 
                length = fileList.length,
                index = 0,
                fileValue,
                fileExtension,
                successList = [],
                errorList = [];
            let shopExtensionList = _this.makerInfoObj[_this.shopType].extensionList;
            uploadFile(index);

            function uploadFile() {
                if (index >= length) {
                    document.getElementById("loader").remove();
                    console.log("success", successList);
                    console.log("error", errorList);
                    console.log("total", fileList);
                    return;
                }
                fileValue = fileList[index];
                // 判断文件后缀是否属于合法后缀
                fileExtension = codeMain.path.extname(fileValue).replace(".", "");
                if (!shopExtensionList.includes(fileExtension)) {
                    errorList.push({
                        fileValue: fileValue,
                        msg: `文件后缀不正确`
                    });
                    ++index;
                    uploadFile();
                    return;
                }
                // 声音、图片使用同一个方法，方法内部获取了声音的长度
                let fd = new FormData();
                let params = {
                    fd: fd,
                    fileValue: fileValue,
                    previewImageValue: previewImageValue
                };
                _this.checkFileAndGetBinary(params).then((fd) => {
                    convertFileToServer(fd, fileValue, (isUploadSuccess, resId) => {
                        if (isUploadSuccess) {
                            successList.push({ fileValue, resId });
                        } else {
                            errorList.push({ fileValue, resId });
                        }
                        console.log(`%c ${fileValue}上传成功?: ${isUploadSuccess}`, "color: green;");
                        ++index;
                        uploadFile();
                    });
                }).catch((msg) => {
                    errorList.push({ 
                        fileValue,
                        msg: `获取文件File对象出错: ${msg}`
                    });
                    ++index;
                    uploadFile();
                });
            }
        }

        function uploadMultiDir(dirValue) {
            // 获取列表
            let dirList = [];
            codeMain.getAllFolderOneLayer(dirValue, dirList);
            let 
                length = dirList.length,
                index = 0,
                fileValue,
                successList = [],
                errorList = [];
            uploadDirFile(index);

            function uploadDirFile() {
                if (index >= length) {
                    document.getElementById("loader").remove();
                    console.log("success", successList);
                    console.log("error", errorList);
                    console.log("total", dirList);
                    return;
                }
                fileValue = dirList[index];
                // 所有类别使用同一个方法，由方法内部判断是否符合规则
                // 必须要有预览图
                let previewImageValue = `${fileValue}.jpg;`;
                let fd = new FormData();
                let params = {
                    fd: fd,
                    fileValue: fileValue,
                    previewImageValue: previewImageValue
                };
                _this.checkFileAndGetBinary(params).then((fd) => {
                    convertFileToServer(fd, fileValue, (isUploadSuccess, resId) => {
                        if (isUploadSuccess) {
                            successList.push({ fileValue, resId });
                        } else {
                            errorList.push({ fileValue, resId });
                        }
                        console.log(`%c ${fileValue}上传成功?: ${isUploadSuccess}`, "color: green;");
                        ++index;
                        uploadDirFile();
                    });
                }).catch((msg) => {
                    errorList.push({ 
                        fileValue,
                        msg: msg
                    });
                    ++index;
                    uploadDirFile();
                });
            }
        }
    }

    /**
     * 资源 btn 点击事件
     * - 上传、修改页面
     */
    resourcesBtnClickHanler(fileInput, nameInput) {
        if (!fileInput){
            alert("逻辑执行不正常，请联系服务提供商!");
        }
        // 根据不同的类型，选中不同的资源(声音、图片、文件夹)
        this.openResDialog("", (filePaths) => {
            let filePath = filePaths && filePaths[0];
            if (!filePath) {
                return;
            }
            // 文件夹中是否有对应的文件
            if (this.isDirType()) {
                let fileList = [];
                codeMain.getFolderFileOneLayer(filePath, fileList);
                if (fileList.length === 0) {
                    alert(codeMain.getPanelLang(343)); // 没有在顶层目录找到任何文件
                    return;
                }
                // 文件夹中是否包含该类型对应的文件
                let msgObj = this.checkContainFile(fileList);
                if (!msgObj.isSuccess) {
                    alert(msgObj.msg);
                    return;
                }
            }
            if (fileInput.tagName === "INPUT") {
                fileInput.value = filePath;
            } else {
                fileInput.innerHTML = filePath;
            }
            if (nameInput && !nameInput.value) {
                nameInput.value = codeMain.path.basename(filePath);
            }
        });
    }

    /**
     * 修改资源属性
     */
    modifyResInfo() {
        // 获取各项信息
        let detailEle = this.popUpShopDetailEle;
        let 
            resId = detailEle.getAttribute("data-resid"),
            classId = detailEle.getAttribute("data-classid"),
            navId = detailEle.getAttribute("data-navid"),
            index = detailEle.getAttribute("data-index"),
            auditStatus = detailEle.getAttribute("data-auditstatus"), // 审核状态
            oldName = detailEle.getElementsByClassName("shop-detail-name-input")[0].getAttribute("data-value"),
            oldDesc = detailEle.getElementsByClassName("shop-detail-desc-input")[0].getAttribute("data-value"),
            oldPrice = detailEle.getElementsByClassName("shop-detail-price-input")[0].getAttribute("data-value"),
            oldTag = detailEle.getElementsByClassName("shop-detail-tag-input")[0].getAttribute("data-value"),
            oldPreviewImg = detailEle.getElementsByClassName("upload-preview-image-link")[0].getAttribute("data-value"),
            oldFileRes = detailEle.getElementsByClassName("upload-file-link")[0].getAttribute("data-value");
        let 
            resName = detailEle.getElementsByClassName("shop-detail-name-input")[0].value,
            resDesc = detailEle.getElementsByClassName("shop-detail-desc-input")[0].value,
            resPrice = detailEle.getElementsByClassName("shop-detail-price-input")[0].value,
            resTag = detailEle.getElementsByClassName("shop-detail-tag-input")[0].value,
            resNav = document.getElementById("navSelect").value,
            resSubNav = document.getElementById("subNavSelect").value,
            previewImg = detailEle.getElementsByClassName("upload-preview-image-link")[0].innerText.trim(),
            fileRes = detailEle.getElementsByClassName("upload-file-link")[0].innerText.trim();
        let navValueId = resNav + resSubNav;
        let _this = this;
        if (resDesc.length > 255) { // string: 0-255
            alert(codeMain.getPanelLang(350)); // 描述需要为10-255位的字符串
            return;
        }
        if (!navValueId || navValueId.length > 4 || isNaN(Number(navValueId))) { // int: 1-4
            alert(codeMain.getPanelLang(351)); // 类别需要为1-4位的数字
            return;
        }
        if (!resPrice || resPrice.length > 30) { // string: 1-30
            alert(codeMain.getPanelLang(352)); // 价格需要为1-30位的字符串
            return;
        }
        if (!codeMain.tool.isMoney(resPrice)) {
            alert(codeMain.getPanelLang(378)); // 无法正确解析价格
            return;
        }
        if (resTag.length > 120) { // string: 0-120
            alert(codeMain.getPanelLang(353)); // 标签需要为0-120位的字符串
            return;
        }

        if (!resId || !classId || !navId) {
            alert("信息不足，请联系服务提供商");
            return;
        }
        if (oldName === resName && oldDesc === resDesc && oldPrice === resPrice && oldTag === resTag 
            && navId === navValueId && oldPreviewImg === previewImg && oldFileRes === fileRes) {
            alert("检测到没有任何修改，不需要提交修改");
            return;
        }

        // loading
        let loaderEle = this.createElement("div");
        loaderEle.id = "loader";
        loaderEle.style.display = "flex";
        loaderEle.innerHTML = `
            <div class="load-container load4">
                <div class="loader">Loading...</div>
            </div>
        `;
        detailEle.appendChild(loaderEle);
        
        let fd2 = new FormData();
        let params = {
            fd: fd2
        };
        if (oldFileRes !== fileRes) {
            params.fileValue = fileRes;
        }
        if (oldPreviewImg !== previewImg) {
            params.previewImageValue = previewImg;
        }
        this.checkFileAndGetBinary(params).then((fd2) => {
            this.getLayaMakerToken((token, devuid) => {
                let publicURL = `${codeMain.layamakerAPPURL}/index`; // 请求资源列表
                fd2.append("access_token", token);
                fd2.append("act", "update");
                fd2.append("config_name", "res_cloud");
                fd2.append("res_id", Number(resId));
                // 如果之前是未发布状态，将其状态改为已发布，使其进入审核状态
                // TODO 更好的做法是修改了资源就将其进入审核状态，但是因为现在只有我在使用，并且配合幻境工厂修改频繁，没必要做这件事
                if (auditStatus === "0") {
                    fd2.append("publish", 1);
                }
                if (oldName !== resName) {
                    fd2.append("res_filename", resName);
                }
                if (oldDesc !== resDesc) {
                    fd2.append("res_desc", resDesc);
                }
                if (oldPrice !== resPrice) {
                    fd2.append("res_price", resPrice);
                }
                if (oldTag !== resTag) {
                    fd2.append("res_tag", resTag);
                }
                if (navId !== navValueId) {
                    fd2.append("res_nav", Number(navValueId));
                }
                // 提交请求
                // 之前都是在整理数据
                let serverResParams = {
                    url: publicURL,
                    content: fd2
                };
                codeMain.postInfoToServer(serverResParams, (responseText) => {
                    document.getElementById("loader").remove();
                    let reObj;
                    try {
                        reObj = JSON.parse(responseText);
                    } catch(e) {
                        reObj = null;
                    }
                    if (reObj && reObj.ret === 0) {
                        alert("修改成功");
                        // 找到对应的值
                        let 
                            oldNavId = navId.substr(0, 2),
                            oldSubNavId = navId.substr(2, 2);
                        let oldList = _this.shopInfoObj.resNavSortObj[oldNavId][oldSubNavId].list;
                        let oldResObj = oldList[index];
                        // 修改对应的值
                        let 
                            _data = reObj.data,
                            key, value;
                        for (key in _data) {
                            value = _data[key];
                            oldResObj[key]= value;
                        }
                        // 这里的时间并不准确，但是不修改也不太好
                        let now = new Date();
                        oldResObj.updated_at = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
                        // 移动到对应的分组（如果分组变化了）
                        if (navId !== navValueId) {
                            oldList.splice(index, 1);
                            _this.shopInfoObj.resNavSortObj[resNav][resSubNav].list.unshift(oldResObj);
                        }
                        _this.createMainContentHTML("refresh");
                    } else {
                        alert(responseText);
                    }
                });
            });
        }).catch((msg) => {
            if (msg) {
                alert(msg);
            }
            let loaderEle = document.getElementById("loader");
            loaderEle.remove();
        });
    }

    /**
     * 获取文件和预览图的File对象，所有获取稳健对象的操作都在这里进行
     * - 传过来三个参数，分别是formdata、文件路径和预览图路径，如果通过了判断，则返回FormData，如果没有通过判断，则reject回去msg
     * - 检查文件(夹)是否符合规范，包括大小是否符合规范，文件夹内是否有对应类型等
     * - 如果有预览图，判断预览图是否符合规则
     * - 如果是声音则同时获取长度
     * - 如果是需要上传文件夹的资源类型，则打包zip
     * - 最后将组织好的FormData返回
     * - * 目前调用位置有: 上传panel(上传单个文件、上传文件夹)、修改资源panel
     */
    checkFileAndGetBinary(params) {
        return new Promise((resolve, reject) => {
            let 
                fd = params.fd, // 需要返回的FormData
                fileValue = params.fileValue,
                previewImageValue = params.previewImageValue;
            if (!fileValue && !previewImageValue) {
                resolve(fd);
            }
            // 0) 检查文件夹内是否有对应类型
            let isUploadDir = this.isDirType();
            // 0.1) 上传声音、图片，检查是否符合要求
            if (!isUploadDir && fileValue) {
                let shopExtensionList = this.makerInfoObj[this.shopType].extensionList;
                let fileExtension = codeMain.path.extname(fileValue).replace(".", "");
                if (!shopExtensionList.includes(fileExtension)) {
                    reject("文件后缀不正确");
                    return;
                }
            }

            // 0.2) 上传zip包，检查文件夹中是否有对应的文件
            if (isUploadDir && fileValue) {
                let fileList = [];
                codeMain.getFolderFileOneLayer(fileValue, fileList);
                if (fileList.length === 0) {
                    reject(codeMain.getPanelLang(343)); // 没有在顶层目录找到任何文件
                    return;
                }
                // 文件夹中是否包含该类型对应的文件
                let msgObj = this.checkContainFile(fileList);
                if (!msgObj.isSuccess) {
                    reject(msgObj.msg);
                    return;
                }
            }

            // 1) 处理预览图，并将预览图转换为File对象
            let 
                fileSizeLimit = 5, // 文件大小限制
                prevImgSizeLimit = 3; // 预览图大小限制
            if (previewImageValue) {
                let previewImageList = previewImageValue.split(";");
                previewImageList.length -= 1;
                let previewImageFile;
                for (let i = 0; i < previewImageList.length; i++) {
                    // 检查预览图是否存在
                    if (!codeMain.fs.existsSync(previewImageList[i])) {
                        reject(`预览图不存在: ${previewImageList[i]}`);
                        return;
                    }
                    previewImageFile = codeMain.tool.getFile(previewImageList[i]);
                    // 预览图不能超过3M
                    if (previewImageFile.size / 1024 / 1024 > prevImgSizeLimit) {
                        reject(`${codeMain.getPanelLang(407)}: ${prevImgSizeLimit}M`);
                        return;
                    }
                    fd.append("preview_img[]", previewImageFile);
                }
            }
            if (!fileValue) {
                resolve(fd);
            }

            // 2) 查看文件大小是否符合规范，如果合法则组织FormData并返回
            if (fileValue) {
                // 2.1) 处理不用打包成zip包的资源，包括声音、图片
                if (!isUploadDir) { // 声音、图片
                    if ("pic" === this.shopType) {
                        fileSizeLimit = 3; // 图片，即使是资源也限制为 3 M
                    }
                    // 2.1.1) 处理声音的情况
                    if (this.shopType === "sound") {
                        codeMain.tool.getAudioDuration(fileValue).then((_duration) => {
                            fd.append("res_extends", JSON.stringify({ // 音频时长
                                duration: _duration || 0
                            }));
                            convertFileToBinary(fileValue);
                        });
                        return;
                    }
                    // 2.1.2) 处理图片的情况
                    convertFileToBinary(fileValue);
                    return;
                }
                // 2.2) 处理需要打包成zip包的资源
                let zipNameValue = `${codeMain.path.basename(fileValue)}.zip`;
                codeMain.tool.zipDir(fileValue, zipNameValue).then((zipDirPath) => {
                    convertFileToBinary(zipDirPath);
                }).catch((e) => {
                    reject("上传资源出错");
                });
            }

            function convertFileToBinary(filePath) {
                // 将资源转换成File对象
                let binaryFile = codeMain.tool.getFile(filePath);
                // 资源不能超过 5 M
                if (binaryFile.size / 1024 / 1024 > fileSizeLimit) {
                    reject(`${codeMain.getPanelLang(406)}: ${fileSizeLimit}M`);
                    return;
                }
                fd.append("res_file", binaryFile);
                resolve(fd);
            }
        });
    }

    /**
     * 下线 按钮
     */
    downLine() {
        let con = confirm("下线之后无法在列表中显示，确认下线?");
        if (!con) {
            return;
        }
        let detailEle = this.popUpShopDetailEle;
        // loading
        let loaderEle = this.createElement("div");
        loaderEle.id = "loader";
        loaderEle.style.display = "flex";
        loaderEle.innerHTML = `
            <div class="load-container load4">
                <div class="loader">Loading...</div>
            </div>
        `;
        detailEle.appendChild(loaderEle);

        // 获取各项信息
        let 
            resId = detailEle.getAttribute("data-resid"),
            navId = detailEle.getAttribute("data-navid"),
            index = detailEle.getAttribute("data-index");
        this.getLayaMakerToken((token, devuid) => {
            let publicURL = `${codeMain.layamakerAPPURL}/index`; // 请求资源列表
            let fd2 = new FormData();
            fd2.append("access_token", token);
            fd2.append("act", "downline");
            fd2.append("config_name", "res_cloud");
            fd2.append("res_id", Number(resId));
            let serverResParams = {
                url: publicURL,
                content: fd2
            };
            codeMain.postInfoToServer(serverResParams, (responseText) => {
                document.getElementById("loader").remove();
                let reObj;
                try {
                    reObj = JSON.parse(responseText);
                } catch(e) {
                    reObj = null;
                }
                if (reObj && reObj.ret === 0) {
                    alert("修改成功");
                    // 找到对应的值
                    let 
                        oldNavId = navId.substr(0, 2),
                        oldSubNavId = navId.substr(2, 2);
                    let oldList = this.shopInfoObj.resNavSortObj[oldNavId][oldSubNavId].list;
                    oldList.splice(index, 1);
                    this.createMainContentHTML("refresh");
                } else {
                    alert(responseText);
                }
            });
        });
    }

    /**
     * 获取本地资源，返回本地地址
     * - 根据当前资源类型自动选择
     * - 支持图片、声音、模型等
     */
    openResDialog(options, func) {
        let _options = options;
        if (!_options) {
            let optionsList = {
                "pic": {
                    filters: [{name: 'image', extensions: this.makerInfoObj["pic"].extensionList}],
                    properties: ["openFile"]
                },
                "sound": {
                    filters: [{name: 'sound', extensions: this.makerInfoObj["sound"].extensionList}],
                    properties: ["openFile"]
                },
                "font": {
                    filters: [{name: 'font', extensions: this.makerInfoObj["font"].extensionList}],
                    properties: ["openFile"]
                },
                "common": {
                    filters: [{name: this.shopType}],
                    properties: ["openDirectory"]
                }
            };
            _options = optionsList[this.shopType];
            if (!_options) {
                _options = optionsList['common'];
            }
        }
        codeMain.remote.dialog.showOpenDialog(_options, function(filePaths) {
            func instanceof Function && func(filePaths);
        });
    }

    /**
     * 拖动文件到上传资源input
     * - 仅在这种操作模式下，图片、声音能够添加文件夹
     */
    handleDropFileToFileInput(e) {
        e.preventDefault();

        let parentTarget = e.currentTarget,
            uploadInputEle = parentTarget.getElementsByClassName("upload-file-input")[0],
            nameInputEle = parentTarget.getElementsByClassName("upload-name-input")[0],
            filePath = e.dataTransfer.files[0].path,
            r = fs.lstatSync(filePath),
            fileExtension = codeMain.path.extname(filePath).replace(".", "");
        let shopExtensionList = this.makerInfoObj[this.shopType].extensionList;

        if (this.shopType === "pic") { // 1) 图片
            if (r.isDirectory() || shopExtensionList.includes(fileExtension)) {
                handleInputValue();
            }
        } else if (this.shopType === "sound") { // 2) 声音
            if (r.isDirectory() || shopExtensionList.includes(fileExtension)) {
                handleInputValue();
            }
        } else if (this.shopType === "font") { // 3) 字体
            if (r.isDirectory() || shopExtensionList.includes(fileExtension)) {
                handleInputValue();
            }
        } else { // 3) 需要打包成zip包
            if (r.isDirectory()) {
                handleInputValue();
            }
        }

        function handleInputValue() {
            uploadInputEle.value = filePath;
            if (!nameInputEle.value) {
                nameInputEle.value = codeMain.path.basename(filePath);
            }
        }
    }

    // 上传的文件夹，是否包含该类型对应的文件
    // 只能包含一个
    checkContainFile(fileList) {
        let reMsg = {
            isSuccess: false,
            msg: ''
        };
        let suffix = this.makerInfoObj[this.shopType].extensionList;
        if (!this.isDirType() || !suffix) { // 该类型不是上传文件夹、或者没有特定后缀
            reMsg.msg = `${codeMain.getPanelLang(344)}(${this.shopType})!`; // 不支持该类型文件的上传
        }
        let conIndex = 0;
        fileList.forEach(element => {
            let extName = codeMain.path.extname(element);
            if (suffix.indexOf(extName) !== -1) {
                conIndex++;
            }
        });
        if (conIndex === 0) {
            reMsg.msg = `${codeMain.getPanelLang(345)}(${suffix})`; // 上传的文件夹中没有找到该类型对应的文件
        } else if (conIndex > 1) {
            reMsg.msg = `${suffix}文件数量多于1个`; // (.类型)文件数量多于1个
        } else {
            reMsg.isSuccess = true;
        }
        return reMsg;
    }

    // 删除资源
    // deleteResFromServer(path, func) {
    //     this.getLayaMakerToken((token, devuid) => {
    //         let params = {
    //             url: `${codeMain.makerBaseURL}/game/gameresourcedel?access_token=${token}&&path=${path}`
    //         };
    //         codeMain.getInfoFromServer(params, (responseText) => {
    //             func instanceof Function && func(responseText);
    //         });
    //     });
    // }

    // 获取游戏列表
    // getGameListFromServer(func) {
    //     this.getLayaMakerToken((token, devuid) => {
    //         let params = {
    //             url: `${codeMain.makerBaseURL}/game/getgamebydid?access_token=${token}&&developer_uid=${devuid}`
    //         };
    //         codeMain.getInfoFromServer(params, (responseText) => {
    //             func instanceof Function && func(responseText);
    //         });
    //     });
    // }

    // 是否登录
    isLogin() {
        let loginInfoStr = localStorage.getItem(this.IS_LOGIN_SUCCESS_STR);
        let userInfo = (loginInfoStr && JSON.parse(loginInfoStr)) || {};
        return !!userInfo.token;
    }

    /**
     * 返回登录信息
     * returns object | null
     * object {
     *  token: required
     *  userId: required
     *  username: ?
     *  
     * }
     */
    getLoginInfo() {
        let loginInfoObj;
        try {
            let loginStr;
            loginStr = localStorage.getItem(this.IS_LOGIN_SUCCESS_STR);
            loginInfoObj = loginStr && JSON.parse(loginStr);
            if (!loginInfoObj.token || !loginInfoObj.userId) {
                loginInfoObj = null;
            }
        } catch (e) {
            loginInfoObj = null;
        }
        return loginInfoObj;
    }

    /**
     * 存储登录信息
     */
    setLoginInfo(loginObj) {
        if ("object" !== typeof loginObj || !loginObj.token || !loginObj.userId) {
            return;
        }
        let oldInfo = this.getLoginInfo();
        // 将业务信息保存
        loginObj.isExec = loginObj.isExec || (oldInfo && oldInfo.isExec);
        loginObj.token_master = loginObj.token_master || (oldInfo && oldInfo.token_master);
        loginObj.is_vip = loginObj.is_vip || (oldInfo && oldInfo.is_vip);
        loginObj.is_enterprise = loginObj.is_enterprise || (oldInfo && oldInfo.is_enterprise);
        loginObj.vip_end_at = loginObj.vip_end_at || (oldInfo && oldInfo.vip_end_at);
        loginObj.devuid = loginObj.devuid || (oldInfo && oldInfo.devuid);
        
        localStorage.setItem(this.IS_LOGIN_SUCCESS_STR, JSON.stringify(loginObj));
        if (loginObj.token_master) {
            sessionStorage.setItem("getMasterTokenTime", Date.now());
        }
    }

    /**
     * layamaker
     *  - 创建项目页面
     */
    createLayaMakerPanel() {
        if (this.isLayaMakerPanelShow()) {
            return;
        }
        // 创建新建项目panel
        let layaMakerPanelEle = this.createElement('div');
        layaMakerPanelEle.id = 'layaMakerPanel';
        layaMakerPanelEle.innerHTML = `
        <div class="main-wrapper"></div>
        `;
        // 附加到页面中
        document.body.appendChild(layaMakerPanelEle);
        let panelWrapper = document.getElementById('layaMakerPanel').getElementsByClassName('main-wrapper')[0];
        // loading
        panelWrapper.innerHTML = `
        <div id="loader">
            <div class="load-container load4">
                <div class="loader">Loading...</div>
            </div>
        </div>
        `;

        // TODO @kylin 获取项目列表
        let paramObj = {
            url: ''
        };
        codeMain.getInfoFromServer(paramObj, (responseText) => {
            let resObj;
            try {
                resObj = responseText && JSON.parse(responseText);
            } catch(e) {
                resObj = null;
            }
            // 确定接口返回正确
            // if (!(resObj instanceof Object) || resObj.ret !== 0) {
            //     alert(codeMain.panel[280][langindex]); // 网络错误，请检查网络连接
            //     return;
            // }
            // 显示
            let projectListHTML = `
            <div class="small-image-item-wrapper" data-type="empty">
                <div class="small-image-item-content">
                    <div class="small-img-wrapper">
                        <img class="small-img-item" src="./skins/default/image/ide/res-shop-add.png" style="width: auto; height: auto;"/>
                    </div>
                    <div class="bottom-content">${'LayaAir引擎'}</div>
                </div>
            </div>
            `;
            for (let i = 0; i < 15; i++) {
                projectListHTML += `
                    <div class="small-image-item-wrapper">
                        <div class="small-image-item-content">
                            <div class="small-img-wrapper">
                                <img class="small-img-item" src="${'https://official.layabox.com/laya_data/Chinese/news/2017/08/05/1.jpg'}"/>
                            </div>
                            <div class="bottom-content">${'LayaAir引擎'}</div>
                        </div>
                    </div>
                `;
            }
            panelWrapper.innerHTML = `
                <div class="common-tool-title">
                    <div class="common-tool-icon-wrapper">
                        <img class="common-tool-icon" title="${codeMain.getPanelLang(122)}" src="skins/default/image/ide/layamaker-newpro.png" style="width: 18px; height: 20px;">
                    </div>
                    <div class="common-tool-title-content">${codeMain.getPanelLang(122)}</div>
                    <div class="common-tool-close"></div>
                </div>
                <div class="category-wrapper">
                    <div class="category-list">
                        <span class="category-item">分类</span>
                        <span class="category-item">推荐</span>
                        <span class="category-item">剧情游戏</span>
                        <span class="category-item">推理游戏</span>
                        <span class="category-item">射击游戏</span>
                        <span class="category-item">企业宣传</span>
                        <span class="category-item">产品营销</span>
                        <span class="category-item">动漫</span>
                        <span class="category-item">课件</span>
                    </div>
                    <div style="display: flex;">
                        <div class="category-search">
                            <input class="search-input"/>
                            <div class="img"></div>
                        </div>
                        <div class="category-pagination">
                            <span class="pagination-item pagination-begin"><<</span>
                            <span class="pagination-item pagination-before"><</span>
                            <span class="pagination-item">1</span>
                            <span class="pagination-item">2</span>
                            <span class="pagination-item pagination-dot">...</span>
                            <span class="pagination-item">21</span>
                            <span class="pagination-item pagination-after">></span>
                            <span class="pagination-item pagination-end">>></span>
                        </div>
                    </div>
                </div>
                <div class="project-wrapper">
                    ${projectListHTML}
                </div>
            `;
            let title = layaMakerPanelEle.getElementsByClassName("common-tool-title")[0];
            __Layadrag(layaMakerPanelEle, title);
            this.bindLayaMakerEventListener();
        });
    }
    bindLayaMakerEventListener() {
        // 点击事件
        this.eventFunc['newProjectClick'] = () => {
            let target = event.target;
            let parentNodeEle = target;
            for (let i = 0; i < 10; i++) {
                if (!parentNodeEle) { // 没有父元素了，return
                    return;
                }
                let className = parentNodeEle.className;
                if (typeof className !== "string") {
                    return;
                }
                if (className === 'small-image-item-wrapper') { // 项目item
                    let type = parentNodeEle.getAttribute("data-type");
                    this.createLayaMakerProject(type);
                    return;
                } else if (className === 'common-tool-close') { // 关闭按钮
                    this.destoryLayaMakerPanel();
                    return;
                } else if (className === 'category-item') { // 分类
                    // loading
                    // 网络请求
                } else if (className.indexOf('pagination-item') !== -1) { // 分页
                    // loading
                    // 网络请求
                }
                parentNodeEle = parentNodeEle.parentNode;
            }
        }
        // 搜索事件
        this.eventFunc["newProjectSearch"] = () => {
            let target = event.target,
                keyCode = event.which || event.keyCode,
                searchStr = target.value;
            // 1) 回车更新列表或者 2) 随着字符变化，一直更新列表
            // 一个问题，列表很大的话，我是不是只搜索当前列表的内容?
            if (keyCode === 13) { // 回车
                // 更新列表
            }
        }
        document.getElementById('layaMakerPanel').addEventListener('click', this.eventFunc['newProjectClick'], false);
        let searchEle = document.getElementById('layaMakerPanel').getElementsByClassName("search-input")[0];
        searchEle.addEventListener('keyup', this.eventFunc['newProjectSearch'], false);
    }
    // 新建layamaker项目
    createLayaMakerProject(type) {
        this.getLayaMakerToken((token) => {
            if (!token) {
                return;
            }
            // 弹出新建信息panel
            let makerInfoPanel = this.createElement('div');
            makerInfoPanel.className = "maker-newpro-info";
            makerInfoPanel.innerHTML = `
                <div class="maker-wrapper common-panel-wrapper">
                    <div class="common-tool-title">
                        <div class="common-tool-icon-wrapper">
                            <img class="common-tool-icon" title="${codeMain.getPanelLang(8)}" src="skins/default/image/ide/layamaker-newpro.png" style="width: 18px; height: 20px;">
                        </div>
                        <div class="common-tool-title-content">${codeMain.getPanelLang(8)}</div>
                        <div class="common-tool-close"></div>
                    </div>
                    <div class="maker-newpro-info-wrapper">
                        <input class="maker-input maker-name" placeholder="${codeMain.getPanelLang(59)}">
                        <input class="maker-input maker-file-path" placeholder="${codeMain.getPanelLang(123)}" style="top: 140px;">
                        <button class="common-skins-file-btn maker-file-path-btn" style="top: 140px;">${codeMain.getPanelLang(22)}</button>
                        <button class="layaBtnCustum" style="top: 234px; left: 206px;">${codeMain.getPanelLang(8)}</button>
                        <span class="maker-pop-error-info" style="display: none;"></span>
                    </div>
                </div>
            `;
            codeMain.addPopLayer(makerInfoPanel);
            let titleEle = makerInfoPanel.getElementsByClassName("common-tool-title")[0];
            __Layadrag(makerInfoPanel, titleEle);

            let 
                fileNameEle = makerInfoPanel.getElementsByClassName("maker-name")[0],
                filePathEle = makerInfoPanel.getElementsByClassName("maker-file-path")[0];
            let 
                makerCreateInfoStr = localStorage.getItem("makerCreateInfo"),
                makerCreateInfoObj = {};
            if (makerCreateInfoStr) {
                try {
                    makerCreateInfoObj = JSON.parse(makerCreateInfoStr);
                    if (!(makerCreateInfoObj instanceof Object)) {
                        makerCreateInfoObj = {};
                    }
                } catch (e) {
                    makerCreateInfoObj = {};
                }
            }
            // 如果名字和地址没有值，比如第一次进入或者数据坏掉了，设置默认值
            fileNameEle.value = makerCreateInfoObj.name || "maker";
            try {
                filePathEle.value = makerCreateInfoObj.path || remote.app.getPath("documents") + path.sep + "layamaker";
            } catch(e) {
                console.error(e);
                alert("获取系统路径出错，请手动设置项目路径!");
            }
            makerInfoPanel.addEventListener("click", () => {
                let target = event.target;
                let parentNodeEle = target;
                for (let i = 0; i < 10; i++) {
                    if (!parentNodeEle) { // 没有父元素了，return
                        return;
                    }
                    let className = parentNodeEle.className;
                    if (typeof className !== "string") {
                        return;
                    }
                    if (className === 'common-tool-close') { // 关闭
                        codeMain.removePopLayer(makerInfoPanel);
                    } else if (className.indexOf("maker-file-path-btn") !== -1) { // 项目路径
                        let oldValue = filePathEle.value,
                            layaDialog = remote.dialog;
                        layaDialog.showOpenDialog({
                            properties: ["openDirectory", 'createDirectory'],
                            defaultPath: oldValue
                        }, function(p) {
                            if (p) {
                                filePathEle.value = p[0];
                            }
                        });
                    } else if (className === "layaBtnCustum") { // 确定
                        let 
                            filePath = filePathEle.value,
                            fileName = fileNameEle.value,
                            fileFullPath = codeMain.path.join(filePath, fileName);
                        if (!fileName) {
                            alert('项目名称不能为空');
                            return;
                        }
                        if (!filePath.length) {
                            alert("没有填写项目路径");
                            return;
                        }
                        if (fs.existsSync(fileFullPath)) { // 文件夹非空
                            if (fs.readdirSync(fileFullPath).length > 0) {
                                alert(`${codeMain.getPanelLang(299)}`);
                                return;
                            }
                        }

                        // loading效果
                        let loaderWrapper = this.createElement("div");
                        loaderWrapper.innerHTML = `
                        <div id="loader">
                            <div class="load-container load4">
                                <div class="loader">Loading...</div>
                            </div>
                        </div>
                        `;
                        makerInfoPanel.getElementsByClassName("maker-wrapper")[0].appendChild(loaderWrapper);
                        
                        let fd = new FormData();
                        fd.append("access_token", token);
                        let infoObj = {
                            url: `${codeMain.layamakerAPPURL}/appadd`, // 创建游戏
                            content: fd
                        };
                        codeMain.postInfoToServer(infoObj).then((re) => {
                            let _infoObj2;
                            try {
                                _infoObj2 = re && JSON.parse(re);
                            } catch(e) {
                                _infoObj2 = null;
                            }
                            if (!_infoObj2 || 'object' !== typeof _infoObj2 || _infoObj2.ret !== 0) {
                                let errMsg = `infoObj=${JSON.stringify(infoObj)}\n re=${JSON.stringify(_infoObj2)}`;
                                throw new Error(errMsg);
                                alert(codeMain.getPanelLang(280)); // 网络错误，请检查网络连接
                                return;
                            }
                            // 将appid保存到项目中和sessionStorage中
                            let appId = _infoObj2.data.appid;
                            sessionStorage.setItem('appId', appId);
                            console.log(`添加成功, appId: ${appId}`);

                            // 将项目信息保存
                            let createObj = {
                                name: fileName,
                                path: filePath
                            };
                            localStorage.setItem("makerCreateInfo", JSON.stringify(createObj));

                            // 如果文件夹不存在，创建文件夹
                            codeMain.mkdirsSync(fileFullPath);

                            // 新建空项目
                            if (type === "empty") {
                                let layaZipPath = path.join(__dirname, "../", "../", "laya", "code", "other", "layamaker");
                                codeMain.copyDir(layaZipPath, fileFullPath).then(() => {
                                    var obj = {
                                        proName: fileName,
                                        layaProType: 101,
                                        appid: appId,
                                        makerVersion: codeMain._sysConfig.makerVersion,
                                    };
                                    let params = {
                                        notCopyEmpty: true,
                                    };
                                    codeMain.createNewPro(fileFullPath, "", "", obj, params);
                                    codeMain.removePopLayer(makerInfoPanel);
                                    this.destoryLayaMakerPanel();
                                });
                                return;
                            }
                            codeMain.tool.downAndExtractZip("http://118.89.114.231:10003/download/kylin_zdd/maker/2d_ts_1018_001.zip", fileFullPath).then(() => {
                                console.log("下载解压maker包成功了!");
                                // 这一段和 skipBtn.onmousedown 基本一致
                                var obj = {
                                    proName: fileName,
                                    layaProType: 101,
                                    appid: appId,
                                    makerVersion: codeMain._sysConfig.makerVersion,
                                };
                                let params = {
                                    notCopyEmpty: true,
                                };
                                codeMain.createNewPro(fileFullPath, "", "", obj, params);
                                codeMain.removePopLayer(makerInfoPanel);
                                this.destoryLayaMakerPanel();
                            }).catch((err) => {
                                alert("下载解压 maker压缩包 出错了!");
                                throw err;
                            });
                        }).catch((e) => {
                            alert(`${codeMain.getPanelLang(280)}: ${e}`);
                            throw e;
                        });
                    }
                    parentNodeEle = parentNodeEle.parentNode;
                }
            });
        });
    }
    destoryLayaMakerPanel() {
        // 取消事件绑定
        document.getElementById('layaMakerPanel').removeEventListener('click', this.eventFunc['newProjectClick']);
        let searchEle = document.getElementById('layaMakerPanel').getElementsByClassName("search-input")[0];
        searchEle.removeEventListener('keyup', this.eventFunc['newProjectSearch']);
        document.getElementById('layaMakerPanel').remove();
    }
    // 获取token，layamaker项目使用
    getLayaMakerToken(func) {
        if (window.globalMode !== codeMain.globalModeType.layamaker) {
            alert("IDE不处于layamaker模式");
            return;
        }
        if (!window.cloudProject || !window.cloudProject.userId) { // 未登录
            return;
        }
        // 检查token是否合法
        this.checkToken((token, devuid) => {
            if (token && devuid) {
                console.log(`%c 使用了缓存token`, "color: green;");
                func instanceof Function && func(token, devuid);
            } else {
                // 请求新的token
                let username = window.cloudProject.username;
                let getInfoObj = {
                    url: `${codeMain.makerBaseURL}/auth/reg_login?userId=${window.cloudProject.userId}&username=${username}`
                };
                codeMain.getInfoFromServer(getInfoObj, (re) => {
                    let _infoObj;
                    try {
                        _infoObj = re && JSON.parse(re);
                    } catch(e) {
                        _infoObj = null;
                    }
                    if (!_infoObj || 'object' !== typeof _infoObj || _infoObj.ret !== 0) {
                        let errMsg = `getInfoObj=${JSON.stringify(getInfoObj)}\n re=${JSON.stringify(_infoObj)}`;
                        throw new Error(errMsg);
                        alert(codeMain.getPanelLang(280)); // 网络错误，请检查网络连接
                        return;
                    }
                    let token = _infoObj.data && _infoObj.data.token;
                    let devuid = _infoObj.data && _infoObj.data.developer_uid;
                    // 将新的token存入
                    let loginInfo = this.getLoginInfo();
                    if (loginInfo) {
                        loginInfo.token= token;
                        loginInfo.devuid= devuid;
                        this.setLoginInfo(loginInfo);
                    }
                    console.log(`%c 重新请求了token`, "color: green;");
                    func instanceof Function && func(token, devuid);
                });
            }
        });
    }
    checkToken(func) {
        let layamakerTokenInfo = this.getLoginInfo();
        if (layamakerTokenInfo && layamakerTokenInfo.token && layamakerTokenInfo.devuid) {
            let 
                token = layamakerTokenInfo.token,
                devuid = layamakerTokenInfo.devuid;
            let checkTokenInfo = {
                url: `${codeMain.makerBaseURL}/auth/checktoken?access_token=${token}`
            };
            codeMain.getInfoFromServer(checkTokenInfo, (_data)=> {
                let data;
                try {
                    data = _data && JSON.parse(_data);
                } catch(e) {
                    data = null;
                }
                if (data && data.ret === 0) {
                    func instanceof Function && func(token, devuid);
                } else {
                    console.log("%c 请求了token，token不合法", "color: green;");
                    console.log(_data);
                    func instanceof Function && func();
                }
            });
            return;
        }
        func instanceof Function && func();
    }
    getProjectPathByAppId(appId) {
        return codeMain.remote.app.getPath('userData') + codeMain.path.sep + 'layamaker' + codeMain.path.sep + appId;
    }
    isLayaMakerPanelShow() {
        return !!document.getElementById('layaMakerPanel');
    }
    // end. layamaker

    createElement(type) {
        let _type = type ? type : 'div';
        let ele = document.createElement(_type);
        return ele;
    }
}
module.exports = layaPage;